-
Notifications
You must be signed in to change notification settings - Fork 7.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(css-tricks): add new routes for css-tricks #18066
base: master
Are you sure you want to change the base?
Conversation
Successfully generated as following: http://localhost:1200/css-tricks/articles - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Articles - CSS-Tricks</title>
<link>https://css-tricks.com/category/articles/</link>
<atom:link href="http://localhost:1200/css-tricks/articles" rel="self" type="application/rss+xml"></atom:link>
<description>Latest Articles - CSS-Tricks - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Tue, 07 Jan 2025 10:24:37 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>The Importance of Investing in Soft Skills in the Age of AI</title>
<description><p>I’ll set out my stall and let you know I am still an AI skeptic. Heck, I still wrap “AI” in quotes a lot of the time I talk about it. I am, however, skeptical of the&nbsp;<em>present</em>, rather than the future. I wouldn’t say I’m positive or even excited about where AI is going, but there’s an inevitability that in development circles, it will be further engrained in our work.</p>
<p>We joke in the industry that the suggestions that AI gives us are more often than not,&nbsp;terrible, but that will only improve in time. A good basis for that theory is how fast generative AI has improved with image and video generation. Sure, generated images still have that “shrink-wrapped” look about them, and generated images of people have extra… um…&nbsp;<em>limbs</em>, but consider how much generated AI images have improved, even in the last 12 months.</p>
<p>There’s also the case that VC money is seemingly exclusively being invested in AI, industry-wide. Pair that with a continuously turbulent tech recruitment situation, with endless major layoffs and even a skeptic like myself can see the writing on the wall with how our jobs as developers are going to be affected.</p>
<p>The biggest risk factor I can foresee is that&nbsp;<strong>if your sole responsibility is to write code, your job is almost certainly at risk</strong>. I don’t think this is an imminent risk in a lot of cases, but as generative AI improves its code output — just like it has for images and video — it’s only a matter of time before it becomes a redundancy risk for actual human developers.</p>
<p>Do I think this is right? Absolutely not. Do I think it’s time to panic? Not&nbsp;<em>yet</em>, but I do see a lot of value in evolving your skillset&nbsp;<em>beyond</em>&nbsp;writing code. I especially see the value in improving your soft skills.</p>
<span id="more-383383"></span>
<h2 class="wp-block-heading" id="what-are-soft-skills"><a href="https://css-tricks.com/the-importance-of-investing-in-soft-skills-in-the-age-of-ai/#aa-what-are-soft-skills" aria-hidden="true" class="aal_anchor" id="aa-what-are-soft-skills"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What are soft skills?</h2>
<p>A good way to think of soft skills is that they are&nbsp;<strong>life skills</strong>. Soft skills include:</p>
<ul class="wp-block-list">
<li>communicating with others,</li>
<li>organizing yourself and others,</li>
<li>making decisions, and</li>
<li>adapting to difficult situations.</li>
</ul>
<p>I believe so much in soft skills that I call them&nbsp;<strong>core skills</strong>&nbsp;and for the rest of this article, I’ll refer to them as&nbsp;<strong>core skills</strong>, to underline their importance.</p>
<p>The path to becoming a truly great developer is down to more than just coding. It comes down to how you approach everything else, like communication, giving and receiving feedback, finding a pragmatic solution, planning — and even&nbsp;<a href="https://css-tricks.com/videos/169-how-to-think-like-a-front-end-developer/">thinking like a web developer</a>.</p>
<p>I’ve been working with CSS for over 15 years at this point and a lot has changed in its capabilities. What hasn’t changed though, is the core skills — often called “soft skills” — that are required to push you to the next level. I’ve spent a large chunk of those 15 years as a consultant, helping organizations — both global corporations and small startups — write better CSS. In almost every single case, an improvement of the organization’s core skills was the overarching difference.</p>
<p>The main reason for this is a lot of the time, the organizations I worked with coded themselves into a corner. They’d done that because they just plowed through — Jira ticket after Jira ticket — rather than step back and question, “is our approach actually working?” By focusing on their team’s&nbsp;<strong>core skills</strong>, we were often — and very quickly — able to identify problem areas and come up with pragmatic solutions that were almost never development solutions. These solutions were instead:</p>
<ul class="wp-block-list">
<li>Improving communication and collaboration between design and development teams</li>
<li>Reducing design “hand-off” and instead, making the web-based output the source of truth</li>
<li>Moving slowly and methodically to move fast</li>
<li>Putting a sharp focus on planning and collaboration between developers and designers,&nbsp;<em>way in advance</em>&nbsp;of production work being started</li>
<li>Changing the mindset of “plow on” to taking a step back, thoroughly evaluating the problem, and then developing a collaborative and by proxy,&nbsp;<strong>much simpler</strong>&nbsp;solution</li>
</ul>
<h2 class="wp-block-heading" id="will-improving-my-core-skills-actually-help"><a href="https://css-tricks.com/the-importance-of-investing-in-soft-skills-in-the-age-of-ai/#aa-will-improving-my-core-skills-actually-help" aria-hidden="true" class="aal_anchor" id="aa-will-improving-my-core-skills-actually-help"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Will improving my core skills actually help?</h2>
<p>One thing AI cannot do — and (hopefully) never will be able to do — is&nbsp;<strong>be human</strong>. Core skills — especially communication skills — are very difficult for AI to recreate&nbsp;<em>well</em>&nbsp;because the way we communicate is uniquely&nbsp;<strong>human</strong>.</p>
<p>I’ve been doing this job a&nbsp;<em>long time</em>&nbsp;and something that’s certainly propelled my career is the fact I’ve always been versatile. Having a multifaceted skillset — like in my case, learning CSS and HTML to improve my design work — will only benefit you. It opens up other opportunities for you too, which is especially important with the way the tech industry currently is.</p>
<p>If you’re wondering how to get started on improving your core skills, I’ve got you. I produced a course called&nbsp;<a href="https://piccalil.li/complete-css" rel="noopener">Complete CSS</a>&nbsp;this year but it’s a&nbsp;<em>slight</em>&nbsp;rug-pull because it’s actually a core skills course that uses CSS as a context. You get to learn some iron-clad CSS skills&nbsp;<em>alongside</em>&nbsp;those core skills too, as a bonus. It’s definitely worth&nbsp;<a href="https://piccalil.li/complete-css" rel="noopener">checking out</a>&nbsp;if you are interested in developing your core skills, especially so if you&nbsp;<a href="https://piccalil.li/blog/we-made-an-email-template-to-help-convince-your-boss-to-pay-for-complete-css/" rel="noopener">receive a training budget from your employer</a>.</p>
<h2 class="wp-block-heading" id="wrapping-up"><a href="https://css-tricks.com/the-importance-of-investing-in-soft-skills-in-the-age-of-ai/#aa-wrapping-up" aria-hidden="true" class="aal_anchor" id="aa-wrapping-up"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Wrapping up</h2>
<p>The main message I want to get across is developing your core skills is as important — if not&nbsp;<em>more</em>&nbsp;important — than keeping up to date with the latest CSS or JavaScript thing. It might be uncomfortable for you to do that, but trust me, being able to stand yourself out over AI is only going to be a good thing, and improving your core skills is a sure-fire way to do exactly that.</p>
</description>
<link>https://css-tricks.com/the-importance-of-investing-in-soft-skills-in-the-age-of-ai/</link>
<guid isPermaLink="false">https://css-tricks.com/the-importance-of-investing-in-soft-skills-in-the-age-of-ai/</guid>
<pubDate>Mon, 06 Jan 2025 14:58:46 GMT</pubDate>
<author>Andy Bell</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2021/11/Untitled_Artwork-scaled.jpg" type="image/jpeg"></enclosure>
<category>artificial intelligence</category>
<category>jobs</category>
</item>
<item>
<title>Thank You (2024 Edition)</title>
<description><p>I’ll be honest: writing this post feels like a chore some years. Rounding up and reflecting on what’s happened throughout the year is somewhat obligatory for a site like this, especially when <a href="https://css-tricks.com/thank-you-2007/">it’s a tradition that goes back as far as 2007</a>. <em>“Hey, look at all the cool things we did!”</em></p>
<p>This year is different. Much different. I’m <strong>more</strong> thankful this time around because, last year, I didn’t even get to write this post. At this time last year, I was a full-time student bent on earning a master’s degree while doing part-time contract work.</p>
<p>But now that I’m back, writing this feels so, so, so good. There’s a lot more gusto going into my writing when I say: <em>thank you so very much!</em> It’s because of you and your support for this site that I’m back at my regular job. I’d be remiss if I didn’t say that, so please accept my sincerest gratitude and appreciation. <em>Thank you!</em></p>
<p>Let’s tie a bow on this year and round up what happened around here in 2024.</p>
<span id="more-383295"></span>
<h3 class="wp-block-heading" id="overall-traffic"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-overall-traffic" aria-hidden="true" class="aal_anchor" id="aa-overall-traffic"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Overall traffic</h3>
<p>Is it worth saying anything about traffic? This site’s pageviews had been trending down since 2020 as it has for just about any blog about front-end dev, but it absolutely cratered when the site was on pause for over a year. Things began moving again in late May, but it was probably closer to mid-June when the engine fully turned over and we resumed regular publishing.</p>
<p>And, yes. With regular publishing came a fresh influx of pageviews. Funny how much difference it makes just turning on the lights.</p>
<p>All said and done, we had <strong>26 million</strong> unique pageviews in 2024. That’s exactly what we had in 2023 as traffic went into a tailspin, so I call it a win that we stopped the bleeding and broke even this year.</p>
<h3 class="wp-block-heading" id="publishing"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-publishing" aria-hidden="true" class="aal_anchor" id="aa-publishing"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Publishing</h3>
<p>A little bit of history when it comes to how many articles we publish each year:</p>
<ul class="wp-block-list">
<li><strong>2020:</strong>&nbsp;1,183 articles</li>
<li><strong>2021:</strong>&nbsp;890 articles (site acquired by DigitalOcean)</li>
<li><strong>2022:</strong>&nbsp;390 articles</li>
<li><strong>2023:</strong> 0 articles (site paused)</li>
<li><strong>2024:</strong> 153 articles (site resumed in late June)</li>
</ul>
<p>Going from 0 articles to 153 (including this one) in six months was no small task. I was the only writer on the team until about October. There are only three of us right now; even then, we’re all extremely part-time workers. Between us and <strong>19 guest authors</strong>, I’d say that we outperformed expectations as far as quantity goes — but I’m even more proud of the effort and <em>quality</em> that goes into each one. It’s easy to imagine publishing upwards of 400 articles in 2025 if we maintain the momentum.</p>
<p>Case in point: we published a whopping <strong>three guides</strong> in six months:</p>
<ul class="wp-block-list">
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/">CSS Anchor Positioning</a></li>
<li><a href="https://css-tricks.com/css-length-units/">CSS Length Units</a></li>
<li><a href="https://css-tricks.com/css-selectors/">CSS Selectors</a></li>
</ul>
<p>That might not sound like a lot, so I’ll put it in context. We published just one guide in 2022 and our goal was to write three in all of 2021. We got three this year alone, and they’re all just plain great. I visit Juan’s Anchor Positioning guide as much as — if not more than — I do the ol’ <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">Flexbox</a> and <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">Grid</a> guides.</p>
<p>On top of that, we garnered <strong>34 new additions</strong> to the CSS-Tricks Almanac! That includes all of the features for Anchor Positioning and View Transitions, as well as other new features like <code><a href="https://css-tricks.com/almanac/rules/s/starting-style/">@starting-style</a></code>. And the reason spent so much time in the Almanac is because we made some significant…</p>
<h2 class="wp-block-heading" id="site-updates"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-site-updates" aria-hidden="true" class="aal_anchor" id="aa-site-updates"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Site updates</h2>
<p>This is where the bulk of the year was spent, so let’s break things out into digestible chunks.</p>
<h4 class="wp-block-heading" id="almanac"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-almanac" aria-hidden="true" class="aal_anchor" id="aa-almanac"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Almanac</strong></h4>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" fetchpriority="high" decoding="async" width="2251" height="1051" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=2251%2C1051&amp;ssl=1" alt="Comparing the old Almanac page header with the new one containing links to new sections." class="wp-image-380971" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?w=2251&amp;ssl=1 2251w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=300%2C140&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=1024%2C478&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=768%2C359&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=1536%2C717&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/almanac-header-compare.png?resize=2048%2C956&amp;ssl=1 2048w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><a href="https://css-tricks.com/re-working-the-css-almanac/">We refreshed the entire thing!</a> It used to be just selectors and properties, but now we can write about everything from at-rules and functions to pseudos and everything in between. We still need a lot of help in there, so maybe consider <a href="https://css-tricks.com/guest-writing/">guesting writing with us</a>. 😉</p>
<h4 class="wp-block-heading" id="table-of-contents"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-table-of-contents" aria-hidden="true" class="aal_anchor" id="aa-table-of-contents"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Table of Contents</strong></h4>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" decoding="async" width="2200" height="1822" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=2200%2C1822&amp;ssl=1" alt="Showing the table of contents widget in the right sidebar of an article." class="wp-image-383314" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?w=2200&amp;ssl=1 2200w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=300%2C248&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=1024%2C848&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=768%2C636&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=1536%2C1272&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/table-of-contents-widget.png?resize=2048%2C1696&amp;ssl=1 2048w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>We’ve been embedding anchor links to section headings in articles for several years, <a href="https://css-tricks.com/table-of-contents-block-in-wordpress/">but it required using a WordPress block</a> and it was fairly limiting as far as placement and customization. Now we generate those links automatically and include a conditional that allows us to toggle it on and off for specific articles. I’m working on an article about how it came together that we’ll publish after the holiday break.</p>
<h4 class="wp-block-heading" id="notes"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-notes" aria-hidden="true" class="aal_anchor" id="aa-notes"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Notes</strong></h4>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="3638" height="2066" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=3638%2C2066&amp;ssl=1" alt="The main Notes screen with the first three notecards showing in a row." class="wp-image-383317" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?w=3638&amp;ssl=1 3638w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=300%2C170&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=1024%2C582&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=768%2C436&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=1536%2C872&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?resize=2048%2C1163&amp;ssl=1 2048w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-notes.png?w=3000&amp;ssl=1 3000w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>There’s a <a href="https://css-tricks.com/category/notes/">new section</a> where we take notes on what other people are writing about and share our takeaways with you. The motivation was to lower the barrier to writing more freely. Technical writing takes a lot of care and planning that’s at odds with openly learning and sharing. This way, we have a central spot where you can see what we’re learning and join us along the way — <a href="https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/">such as this set of notes</a> I took from Bramus’ amazing free course on scroll-driven animations.</p>
<h4 class="wp-block-heading" id="links"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-links" aria-hidden="true" class="aal_anchor" id="aa-links"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Links</strong></h4>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="2528" height="2016" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=2528%2C2016&amp;ssl=1" alt="The main Links page with the first two link articles showing in a vertical list that includes information about the link." class="wp-image-383318" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?w=2528&amp;ssl=1 2528w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=300%2C239&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=1024%2C817&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=768%2C612&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=1536%2C1225&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-links.png?resize=2048%2C1633&amp;ssl=1 2048w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><a href="https://css-tricks.com/category/links/">This is another area of the site that got a fresh coat of paint.</a> Well, more than paint. It used to be that links were in the same stream as the rest of the articles, tutorials, and guides we publish. Links are meant to be snappy, sharable bits — conversation starters if you will. Breaking them out of the main feed into their own distinguished section helps reduce the noise on this site while giving links a brighter spotlight with a quicker path to get to the original article. Like when <a href="https://css-tricks.com/anchoreum-a-new-game-for-learning-anchor-positioning/">there’s a new resource for learning Anchor Positioning</a>, we can shoot that out a lot more easily.</p>
<h4 class="wp-block-heading" id="quick-hits"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-quick-hits" aria-hidden="true" class="aal_anchor" id="aa-quick-hits"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Quick Hits</strong></h4>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="2072" height="1644" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=2072%2C1644&amp;ssl=1" alt="The main page for CSS-Tricks Quick Hits showing the first two items in a vertical list." class="wp-image-383337" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?w=2072&amp;ssl=1 2072w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=300%2C238&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=1024%2C812&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=768%2C609&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=1536%2C1219&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-quick-hits.png?resize=2048%2C1625&amp;ssl=1 2048w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>We introduced another new piece of content in the form of brief one-liners that you might typically find us posting on Mastodon or Bluesky. We still post to those platforms <a href="https://css-tricks.com/category/quick-hits/">but now we can write them here on the site</a> and push them out when needed. There’s a lot more flexibility there, even if we haven’t given it a great deal of love just yet.</p>
<h4 class="wp-block-heading" id="picks"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-picks" aria-hidden="true" class="aal_anchor" id="aa-picks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Picks</strong></h4>
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="806" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=1024%2C806&amp;ssl=1" alt="The main CSS-Tricks Picks page showing the first two picks in a vertical stack." class="wp-image-383332" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=1024%2C806&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=300%2C236&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=768%2C605&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=1536%2C1209&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-picks.png?resize=2048%2C1613&amp;ssl=1 2048w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><a href="https://css-tricks.com/picks/">There’s a new feed of the articles we’re reading.</a> It might seem a lot like Links, but the idea is that we can simply “star” something from our RSS reader and it’ll show up in the feed. They’re simply interesting articles that catch our attention that we want to spotlight and share, even if we don’t have any commentary to contribute. <a href="https://css-tricks.com/pages-for-likes/">This was Chris’ brainchild a few years ago</a> and it feels so good to bring it to fruition. I’ll write something up about it after the break, but you can already head over there.</p>
<h4 class="wp-block-heading" id="baseline-status"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-baseline-status" aria-hidden="true" class="aal_anchor" id="aa-baseline-status"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Baseline Status</strong></h4>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="2528" height="1676" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=2528%2C1676&amp;ssl=1" alt="Showing the Baseline Status plugin in the WordPress Plugin Directory." class="wp-image-383323" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?w=2528&amp;ssl=1 2528w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=300%2C199&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=1024%2C679&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=768%2C509&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=1536%2C1018&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/wordpress-baseline-status.png?resize=2048%2C1358&amp;ssl=1 2048w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Ooo, this one’s fun! I saw that <a href="https://web.dev/blog/show-baseline-status" rel="noopener">the Chrome team put out a new web component</a> for embedding web platform browser support information on a page so I set out to make it into a WordPress block we can use throughout the Almanac, which we’re already starting to roll out as content is published or refreshed (such as here in the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-name/#aa-browser-support">anchor-name</a></code> property). I’m still working on a write-up about it, but it’s I’ve already <a href="https://wordpress.org/plugins/baseline-status/" rel="noopener">made it available in the WordPress Plugin Directory</a> if you want to grab it for your WordPress site.</p>
<p>Or, here… I can simply drop it in and show you.</p>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="anchor-positioning"></baseline-status>
<h4 class="wp-block-heading" id="post-slider"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-post-slider" aria-hidden="true" class="aal_anchor" id="aa-post-slider"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><strong>Post Slider</strong></h4>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="2788" height="1062" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=2788%2C1062&amp;ssl=1" alt="Post slider for the latest almanac articles, showing the first five cards in a row." class="wp-image-383326" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?w=2788&amp;ssl=1 2788w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=300%2C114&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=1024%2C390&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=768%2C293&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=1536%2C585&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/css-tricks-post-slider.png?resize=2048%2C780&amp;ssl=1 2048w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>This was one of the first things I made when re-joining the team. We wanted to surface a greater number of articles on <a href="https://css-tricks.com/">the homepage</a> so that it’s easier to find specific types of content, whether it’s the latest five articles, the 10 most recently updated Almanac items or guides, classic CSS tricks from ages ago… that sort of thing. So, we got away from merely showing the 10 most recent articles and developed a series of post sliders that pull from different areas of the site. Converting our existing post slider component into a WordPress block made it more portable and a heckuva lot easier to update the homepage — and any other page or post where we might need a post slider. In fact, that’s another one I can demo for you right here…</p>
<div class="post-slider" style="background:
rgb(38 38 38);">
<div class="post-slider-header header-card">
<h2><a href="https://css-tricks.com/thank-you-2024-edition/#aa-classic-tricks" aria-hidden="true" class="aal_anchor" id="aa-classic-tricks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
Classic Tricks </h2>
<p class="header-card-sponsor">
Timeless CSS gems </p>
</div>
<div class="mini-card-grid">
<article class="mini-card module module-article " id="mini-post-313469">
<time datetime="2020-06-22" title="Originally published Jun 22, 2020">
<strong>
Article
</strong>
on
Oct 6, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-scroll-animation" aria-hidden="true" class="aal_anchor" id="aa-scroll-animation"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/scroll-animation/">
Scroll Animation </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-303153">
<time datetime="2020-02-17" title="Originally published Feb 17, 2020">
<strong>
Article
</strong>
on
Oct 6, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-yellow-flash" aria-hidden="true" class="aal_anchor" id="aa-yellow-flash"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/the-yellow-flash/">
Yellow Flash </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-254582">
<time datetime="2017-05-08" title="Originally published May 8, 2017">
<strong>
Article
</strong>
on
Oct 6, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-self-drawing-shapes" aria-hidden="true" class="aal_anchor" id="aa-self-drawing-shapes"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/make-shape-draw/">
Self-Drawing Shapes </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-305914">
<time datetime="2020-03-30" title="Originally published Mar 30, 2020">
<strong>
Article
</strong>
on
Oct 6, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-scroll-shadows" aria-hidden="true" class="aal_anchor" id="aa-scroll-shadows"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/scroll-shadows/">
Scroll Shadows </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-305930">
<time datetime="2020-03-31" title="Originally published Mar 31, 2020">
<strong>
Article
</strong>
on
May 20, 2020 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-editable-style-blocks" aria-hidden="true" class="aal_anchor" id="aa-editable-style-blocks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/editable-style-blocks/">
Editable Style Blocks </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-304986">
<time datetime="2020-03-15" title="Originally published Mar 15, 2020">
<strong>
Article
</strong>
on
Oct 6, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-scroll-indicator" aria-hidden="true" class="aal_anchor" id="aa-scroll-indicator"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/scroll-indicator/">
Scroll Indicator </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-254474">
<time datetime="2017-05-04" title="Originally published May 4, 2017">
<strong>
Article
</strong>
on
Mar 15, 2020 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-border-triangles" aria-hidden="true" class="aal_anchor" id="aa-border-triangles"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/how-to-make-a-triangle/">
Border Triangles </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-311167">
<time datetime="2020-06-04" title="Originally published Jun 4, 2020">
<strong>
Article
</strong>
on
Oct 3, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-pin-scrolling-to-bottom" aria-hidden="true" class="aal_anchor" id="aa-pin-scrolling-to-bottom"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/greatest-css-tricks/pin-scrolling-to-bottom/">
Pin Scrolling to Bottom </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="mini-card module module-article " id="mini-post-255104">
<time datetime="2017-05-26" title="Originally published May 26, 2017">
<strong>
Article
</strong>
on
Jul 5, 2021 </time>
<h3 class="mini-card-title"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-infinite-scrolling-background-image" aria-hidden="true" class="aal_anchor" id="aa-infinite-scrolling-background-image"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/books/fundamental-css-tactics/infinite-scrolling-background-image/">
Infinite Scrolling Background Image </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
</div>
</div>
<p>So, yeah. This year was heavier on development than many past years. But everything was done with the mindset of making content easier to find, publish, and share. I hope that this is like a little punch on the gas pedal that accelerates our ability to get fresh content out to you.</p>
<h3 class="wp-block-heading" id="2025-goals"><a href="https://css-tricks.com/thank-you-2024-edition/#aa-2025-goals" aria-hidden="true" class="aal_anchor" id="aa-2025-goals"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2025 Goals</h3>
<p>I’m quite reluctant to articulate new goals when there are so many things still in flux, but the planner in me can’t help myself. If I can imagine a day at the end of next year when I’m reflecting on things exactly like this, I’d be happy, nay <em>stoked</em>, if I was able to say we did these things:</p>
<ul class="wp-block-list">
<li><strong>Publish 1-2 new guides.</strong> We already have two in the works! That said, the bar for quality is set very high on these, so it’s still a journey to get from planning to publishing two stellar and chunky guides.</li>
<li><strong>Fill in the Almanac.</strong> My oh my, there is SO much work to do in this little corner of the site. We’ve only got a few pages in the at-rules and functions sections that we recently created and could use <a href="https://css-tricks.com/guest-writing/">all the help we can get</a>.</li>
<li><strong>Restart the newsletter.</strong> This is something I’ve been itching to do. I know I miss reading the newsletter (especially when Robin was writing it) and this community feels so much smaller and quieter ... |
http://localhost:1200/css-tricks/guides - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Latest CSS Guides</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/guides" rel="self" type="application/rss+xml"></atom:link>
<description>Dive deep into CSS features and concepts - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Tue, 07 Jan 2025 10:24:39 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>CSS Anchor Positioning Guide</title>
<description><div class="wp-block-columns are-vertically-aligned-top is-layout-flex wp-container-core-columns-is-layout-1 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66%">
<p>Not long ago, if we wanted a tooltip or popover positioned on top of another element, we would have to set our tooltip’s position to something other than <code>static</code> and use its inset/transform properties to place it <em>exactly</em> where we want. This works, but the element’s position is susceptible to user scrolls, zooming, or animations since the tooltip could overflow off of the screen or wind up in an awkward position. The only way to solve this was using JavaScript to check whenever the tooltip goes out of bounds so we can correct it… again in JavaScript.</p>
<p> CSS Anchor Positioning gives us a simple interface to attach elements next to others just by saying which sides to connect — directly in CSS. It also lets us set a fallback position so that we can avoid the overflow issues we just described. For example, we might set a tooltip element above its anchor but allow it to fold underneath the anchor when it runs out of room to show it above.</p>
<p>Anchor positioning is different from a lot of other features as far as how quickly it’s gained browser support: its <a href="https://www.w3.org/standards/history/css-anchor-position-1/" rel="noopener">first draft was published on June 2023</a> and, just a year later, it was <a href="https://caniuse.com/css-anchor-positioning" rel="noopener">released on Chrome 125</a>. To put it into perspective, the first draft specification for CSS variables <a href="https://www.w3.org/standards/history/css-variables-1/" rel="noopener">was published in 2012</a>, but it took four years for them to gain wide browser support.</p>
<p>So, let’s dig in and learn about things like attaching target elements to anchor elements and positioning and sizing them.</p>
</div>
<div class="wp-block-column is-vertically-aligned-top ticss-986972e6 is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33%"><h2 class="wp-block-heading" id="quick-reference"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-quick-reference" aria-hidden="true" class="aal_anchor" id="aa-quick-reference"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Quick reference</h2>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Define an anchor element */
.anchor {
anchor-name: --my-anchor;
}</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Anchor a target element */
.target {
position: absolute;
position-anchor: --my-anchor;
}</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Position a target element */
.target {
position-area: start end;
}</code></pre>
<div class="wp-block-group sticky-toc"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<details>
<summary>
Table of contents </summary>
<ol class="wp-block-list">
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-basics-and-terminology">Basics and terminology</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-attaching-targets-to-anchors">Attaching targets to anchors</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-positioning-targets">Positioning targets</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-setting-fallback-positions">Setting fallback positions</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-custom-position-and-size-fallbacks">Custom position and size fallbacks</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-multiple-anchors">Multiple anchors</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-accessibility">Accessibility</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-browser-support">Browser support</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-spec-changes">Spec changes</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-known-bugs">Known bugs</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-almanac-references">Almanac references</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-further-reading">Further reading</a></li>
</ol>
</details></div></div>
</div>
</div>
<div style="height:var(--wp--preset--spacing--60)" aria-hidden="true" class="wp-block-spacer"></div>
<details open="">
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-basics-and-terminology" aria-hidden="true" class="aal_anchor" id="aa-basics-and-terminology"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Basics and terminology</h2>
</summary>
<p>At its most basic, CSS Anchor Positioning introduces a completely new way of placing elements on the page relative to one another. To make our lives easier, we’re going to use specific names to clarify which element is connecting to which:</p>
<ul class="wp-block-list">
<li><strong>Anchor:</strong> This is the element used as a reference for positioning other elements, hence the <em>anchor</em><strong> </strong>name.</li>
<li><strong>Target:</strong> This is an absolutely positioned element placed relative to one or more anchors. The <em>target</em> is the name we will use from now on, but you will often find it as just an “absolutely positioned element” in the spec.</li>
</ul>
<p>For the following code examples and demos, you can think of these as just two <code>&lt;div&gt;</code> elements next to one another.</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="anchor"&gt;anchor&lt;/div&gt;
&lt;div class="target"&gt;target&lt;/div&gt;</code></pre>
<p>CSS Anchor Positioning is all about elements with absolute positioning (i.e., <code>position: absolute</code>), so there are also some concepts we have to review before diving in.</p>
<ul class="wp-block-list">
<li><strong>Containing Block:</strong> This is the box that contains the elements. For an absolute element, the containing block is the viewport the closest ancestor with a position other than <code>static</code> or certain values in properties like <a href="https://css-tricks.com/almanac/properties/c/contain/"><code>contain</code></a> or <a href="https://css-tricks.com/almanac/properties/f/filter/"><code>filter</code></a>.</li>
<li><strong>Inset-Modified Containing Block (IMCB):</strong> For an absolute element, inset properties (<code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>, etc.) reduce the size of the containing block into which it is sized and positioned, resulting in a new box called the <em>inset-modified containing block</em>, or IMCB for short. This is a vital concept to know since properties we’re covering in this guide — like <code>position-area</code> and <code>position-try-order</code> — rely on this concept.</li>
</ul>
</details>
<details>
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-attaching-targets-to-anchors" aria-hidden="true" class="aal_anchor" id="aa-attaching-targets-to-anchors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Attaching targets to anchors</h2>
</summary>
<p style="font-size:22px">We’ll first look at the two properties that establish anchor positioning. The first, <code>anchor-name</code>, establishes the anchor element, while the second, <code>position-anchor</code>, attaches a target element to the anchor element.</p>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-2 wp-block-columns-is-layout-flex">
<div class="wp-block-column ticss-30288ed1 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img loading="lazy" data-recalc-dims="1" fetchpriority="high" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1024%2C576&amp;ssl=1" alt="Square labeled as &quot;anchor&quot;" class="wp-image-381095" style="width:300px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?w=1920&amp;ssl=1 1920w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="anchorname"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor-name" aria-hidden="true" class="aal_anchor" id="aa-anchor-name"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>anchor-name</code></h4>
<p>A normal element isn’t an anchor by default — we have to explicitly make an element an anchor. The most common way is by giving it a name, which we can do with the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-name/">anchor-name</a></code> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">anchor-name: none | &lt;dashed-ident&gt;#</code></pre>
<p>The name must be a <code>&lt;dashed-ident&gt;</code>, that is, a custom name prefixed with two dashes (<code>--</code>), like <code>--my-anchor</code> or <code>--MyAnchor</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.anchor {
anchor-name: --my-anchor;
}</code></pre>
<p>This gives us an anchor element. All it needs is something anchored to it. That’s what we call the “target” element which is set with the <code>position-anchor</code> property.</p>
</div></div>
</div>
<div class="wp-block-column ticss-bd46f479 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img loading="lazy" data-recalc-dims="1" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1024%2C576&amp;ssl=1" alt="Square labeled as &quot;target&quot;" class="wp-image-381096" style="width:300px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?w=1920&amp;ssl=1 1920w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-anchor-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-anchor" aria-hidden="true" class="aal_anchor" id="aa-position-anchor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-anchor</code></h4>
<p>The target element is an element with an absolute position linked to an anchor element matching what’s declared on the <code>anchor-name</code> property. This attaches the target element to the anchor element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-anchor: auto | &lt;anchor-element&gt;</code></pre>
<p>It takes a valid <code>&lt;anchor-element&gt;</code>. So, if we establish another element as the “anchor” we can set the target with the <code><a href="https://css-tricks.com/almanac/properties/p/position-anchor/">position-anchor</a></code> property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-anchor: --my-anchor;
}</code></pre>
<p>Normally, if a valid anchor element isn’t found, then other anchor properties and functions will be ignored.</p>
</div></div>
</div>
</div>
</div></div>
</details>
<details>
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-positioning-targets" aria-hidden="true" class="aal_anchor" id="aa-positioning-targets"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Positioning targets</h2>
</summary>
<p style="font-size:22px">Now that we know how to establish an anchor-target relationship, we can work on <strong>positioning</strong> the target element in relation to the anchor element. The following two properties are used to set which side of the anchor element the target is positioned on (<code>position-area</code>) and conditions for hiding the target element when it runs out of room (<code>position-visibility</code>).</p>
<div class="wp-block-columns are-vertically-aligned-top is-layout-flex wp-container-core-columns-is-layout-3 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top ticss-168d39a5 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1024%2C576&amp;ssl=1" alt="Anchor element with target elements spanning around it." class="wp-image-380907" style="width:640px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-area-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-area" aria-hidden="true" class="aal_anchor" id="aa-position-area"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-area</code></h4>
<p>The next step is positioning our target relative to its anchor. The easiest way is to use the <code>position-area</code> property, which creates an imaginary 3×3 grid around the anchor element and lets us place the target in one or more regions of the grid.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-area: auto | &lt;position-area&gt;</code></pre>
<p>It works by setting the row and column of the grid using&nbsp;<strong>logical values</strong>&nbsp;like&nbsp;<code>start</code>&nbsp;and&nbsp;<code>end</code>&nbsp;(dependent on the writing mode);&nbsp;<strong>physical values</strong>&nbsp;like&nbsp;<code>top</code>,&nbsp;<code>left</code>,&nbsp;<code>right</code>,&nbsp;<code>bottom</code>&nbsp;and the&nbsp;<code>center</code>&nbsp;<strong>shared value</strong>, then it will shrink the target’s IMCB into the region of the grid we chose.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: top right;
/* or */
position-area: start end;
}</code></pre>
<p>Logical values refer to the containing block’s writing mode, but if we want to position our target relative to its writing mode we would prefix it with the <code>self</code> value.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: self-start self-end;
}</code></pre>
<p>There is also the <code>center</code> value that can be used in every axis.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: center right;
/* or */
position-area: start center;
}</code></pre>
<p>To place a target across two adjacent grid regions, we can use the prefix <code>span-</code> on any value (that isn’t <code>center</code>) a row or column at a time.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: span-top left;
/* or */
position-area: span-start start;
}</code></pre>
<p>Finally, we can span a target across three adjacent grid regions using the <code>span-all</code> value.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: bottom span-all;
/* or */
position-area: end span-all;
}</code></pre>
<p>You may have noticed that the <code>position-area</code> property doesn’t have a strict order for physical values; writing<code> position-area: top left</code> is the same as <code>position-area: left top</code>, but the order is important for logical value since <code>position-area: start end</code> is completely opposite to <code>position-area: end start</code>.</p>
<p>We can make logical values interchangeable by prefixing them with the desired axis using <code>y-</code>, <code>x-</code>, <code>inline-</code> or <code>block-</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: inline-end block-start;
/* or */
position-area: y-start x-end;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_PormJMG" src="https://codepen.io/anon/embed/preview/PormJMG?height=450&amp;theme-id=1&amp;slug-hash=PormJMG&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed PormJMG" title="CodePen Embed PormJMG" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div></div>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_VwJMxNp" src="https://codepen.io/anon/embed/preview/VwJMxNp?height=450&amp;theme-id=1&amp;slug-hash=VwJMxNp&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed VwJMxNp" title="CodePen Embed VwJMxNp" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div>
<div class="wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group ticss-e32e6402"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1024%2C576&amp;ssl=1" alt="Examples on each position-visibility value: always showing the target, anchors-visible hiding it when the anchor goes out of screen and no-overflow hiding it when the target overflows" class="wp-image-380921" style="width:650px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-visibility-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-visibility" aria-hidden="true" class="aal_anchor" id="aa-position-visibility"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-visibility</code></h4>
<p>It provides certain conditions to hide the target from the viewport.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-visibility: always | anchors-visible | no-overflow</code></pre>
<ul class="wp-block-list">
<li><strong><code>always</code>:</strong> The target is always displayed without regard for its anchors or its overflowing status.</li>
<li><strong><code>no-overflow</code>:</strong> If even after applying the position fallbacks, the target element is still overflowing its containing block, then it is strongly hidden.</li>
<li><strong><code>anchors-visible</code>:</strong> If the <strong>anchor</strong> (not the target) has completely overflowed its containing block or is completely covered by other elements, then the target is strongly hidden.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-visibility: always | anchors-visible | no-overflow</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_XWLzGVe" src="https://codepen.io/anon/embed/preview/XWLzGVe?height=450&amp;theme-id=1&amp;slug-hash=XWLzGVe&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed XWLzGVe" title="CodePen Embed XWLzGVe" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div></div>
</div>
</div>
</details>
<details>
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-setting-fallback-positions" aria-hidden="true" class="aal_anchor" id="aa-setting-fallback-positions"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setting fallback positions</h2>
</summary>
<p style="font-size:22px">Once the target element is positioned against its anchor, we can give the target additional instructions that tell it what to do if it runs out of space. We’ve already looked at the <code>position-visibility</code> property as one way of doing that — we simply tell the element to hide. The following two properties, however, give us more control to <strong>re-position</strong> the target by trying other sides of the anchor (<code>position-try-fallbacks</code>) and the order in which it attempts to re-position itself (<code>position-try-order</code>).</p>
<p>The two properties can be declared together with the <code>position-try</code> shorthand property — we’ll touch on that after we look at the two constituent properties.</p>
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-4 wp-block-columns-is-layout-flex">
<div class="wp-block-column ticss-b9b485c1 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1024%2C576&amp;ssl=1" alt="Examples on each try-tactic: flip-block flipping the target from the top to the bottom, flip-inline from left to right and flip-start from left to top (single value) and top right to left bottom (two values)" class="wp-image-380903" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-try-fallbacks-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-try-fallbacks" aria-hidden="true" class="aal_anchor" id="aa-position-try-fallbacks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-try-fallbacks</code></h4>
<p>This property accepts a list of comma-separated <em>position fallbacks</em> that are tried whenever the target overflows out of space in its containing block. The property attempts to reposition itself using each fallback value until it finds a fit or runs out of options.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try-fallbacks: none | [ [&lt;dashed-ident&gt; || &lt;try-tactic&gt;] | &lt;'inset-area'&gt; ]#</code></pre>
<ul class="wp-block-list">
<li><strong><code>none</code>:</strong> Leaves the target’s position options list empty.</li>
<li><strong><code>&lt;dashed-ident&gt;</code>:</strong> Adds to the options list a custom <code><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor-at-rule">@position-try</a></code> fallback with the given name. If there isn’t a matching <code>@position-try</code>, the value is ignored.</li>
<li><strong><code>&lt;try-tactic&gt;</code>:</strong> Creates an option list by flipping the target’s current position on one of three axes, each defined by a distinct keyword. They can also be combined to add up their effects.
<ul class="wp-block-list">
<li>The <code>flip-block</code> keyword swaps the values in the block axis.</li>
<li>The <code>flip-inline</code> keyword swaps the values in the inline axis.</li>
<li>The <code>flip-start</code> keyword swaps the values diagonally.</li>
</ul>
</li>
<li><strong><code>&lt;dashed-ident&gt;</code> || <code>&lt;try-tactic&gt;:</code></strong> Combines a custom <code>@try-option</code> and a <code>&lt;try-tactic&gt;</code> to create a single-position fallback. The <code>&lt;try-tactic&gt;</code> keywords can also be combined to sum up their effects.</li>
<li><strong><code>&lt;"position-area"&gt;</code></strong> Uses the <code>position-area</code> syntax to move the anchor to a new position.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try-fallbacks:
--my-custom-position,
--my-custom-position flip-inline,
bottom left;
}</code></pre>
</div></div>
</div>
<div class="wp-block-column ticss-69217be6 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1024%2C576&amp;ssl=1" alt="two targets sorrounding an anchor, positioned where the IMCB is the largest. " class="wp-image-380914" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-try-order-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-try-order" aria-hidden="true" class="aal_anchor" id="aa-position-try-order"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-try-order</code></h4>
<p>This property chooses a new position from the fallback values defined in the <code>position-try-fallbacks</code> property based on which position gives the target the most space. The rest of the options are reordered with the largest available space coming first.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try-order: normal | most-width | most-height | most-block-size | most-inline-size</code></pre>
<p>What exactly does “more space” mean? For each position fallback, it finds the IMCB size for the target. Then it chooses the value that gives the IMCB the widest or tallest size, depending on which option is selected:</p>
<ul class="wp-block-list">
<li><code>most-width</code></li>
<li><code>most-height</code></li>
<li><code>most-block-size</code></li>
<li><code>most-inline-size</code></li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try-fallbacks: --custom-position, flip-start;
position-try-order: most-width;
}</code></pre>
</div></div>
<h4 class="wp-block-heading" id="-position-try-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-try" aria-hidden="true" class="aal_anchor" id="aa-position-try"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>position-try</code></h4>
<p>This is a shorthand property that combines the <code>position-try-fallbacks</code> and <code>position-try-order</code> properties into a single declaration. It accepts first the order and then the list of possible position fallbacks.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try: &lt; "position-try-order" &gt;? &lt; "position-try-fallbacks" &gt;;</code></pre>
<p>So, we can combine both properties into a single style rule:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try: most-width --my-custom-position, flip-inline, bottom left;
}</code></pre>
</div>
</div>
</details>
<details>
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-custom-position-and-size-fallbacks" aria-hidden="true" class="aal_anchor" id="aa-custom-position-and-size-fallbacks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Custom position and size fallbacks</h2>
</summary>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained"><h4 class="wp-block-heading" id="-position-try-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-position-try" aria-hidden="true" class="aal_anchor" id="aa-position-try"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>@position-try</code></h4>
<p>This at-rule defines a custom position fallback for the <code>position-try-fallbacks</code> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@position-try &lt;dashed-ident&gt; {
&lt;declaration-list&gt;
}</code></pre>
<p>It takes various properties for changing a target element’s position and size and grouping them as a new position fallback for the element to try.</p>
<p>Imagine a scenario where you’ve established an anchor-target relationship. You want to position the target element against the anchor’s top-right edge, which is easy enough using the <code>position-area</code> property we saw earlier:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-area: top right;
width: 100px;
}</code></pre>
<p>See how the <code>.target</code> is sized at <code>100px</code>? Maybe it runs out of room on some screens and is no longer able to be displayed at anchor’s the top-right edge. We can supply the <code>.target</code> with the fallbacks we looked at earlier so that it attempts to re-position itself on an edge with more space:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="4,5"><code markup="tt">.target {
position: absolute;
position-area: top right;
position-try-fallbacks: top left;
position-try-order: most-width;
width: 100px;
}</code></pre>
<p>And since we’re being good CSSer’s who strive for clean code, we may as well combine those two properties with the <code>position-try</code> shorthand property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="4"><code markup="tt">.target {
position: absolute;
position-area: top right;
position-try: most-width, flip-inline, bottom left;
width: 100px;
}</code></pre>
<p>So far, so good. We have an anchored target element that starts at the top-right corner of the anchor at <code>100px</code>. If it runs out of space there, it will look at the <code>position-try</code> property and decide whether to reposition the target to the anchor’s top-left corner (declared as <code>flip-inline</code>) or the anchor’s bottom-left corner — whichever offers the most width.</p>
<p>But what if we want to simulataneously <strong>re-size</strong> the target element when it is re-positioned? Maybe the target is simply too dang big to display at <code>100px</code> at either fallback position and we need it to be <code>50px</code> instead. We can use the <code>@position-try</code> to do exactly that:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@position-try --my-custom-position {
position-area: top left;
width: 50px;
}</code></pre>
<p>With that done, we now have a custom property called <code>--my-custom-position</code> that we can use on the <code>position-try</code> shorthand property. In this case, <code>@position-try</code> can replace the <code>flip-inline</code> value since it is the equivalent of <code>top left</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="9"><code markup="tt">@position-try --my-custom-position {
position-area: top left;
width: 50px;
}
.target {
position: absolute;
position-area: top right;
position-try: most-width, --my-custom-position, bottom left;
width: 100px;
}</code></pre>
<p>This way, the <code>.target</code> element’s width is re-sized from <code>100px</code> to <code>50px</code> when it attempts to re-position itself to the anchor’s top-right edge. That’s a nice bit of flexibility that gives us a better chance to make things fit together in any layout.</p>
</div></div>
</div></div>
</details>
<details>
<summary>
<h2><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor-functions" aria-hidden="true" class="aal_anchor" id="aa-anchor-functions"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Anchor functions</h2>
</summary>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-5 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group ticss-9c54673b"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained"><h4 class="wp-block-heading" id="-anchor-"><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor" aria-hidden="true" class="aal_anchor" id="aa-anchor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code>anchor()</code></h4>
<p>You might think of the CSS <code>anchor()</code> function as a shortcut for attaching a target element to an anchor element — specify the anchor, the side we want to attach to, and how large we want the target to be in one fell swoop. But, as we’ll see, the function also opens up the possibility of attaching one target element to multiple anchor elements.</p>
<p>This is the function’s formal syntax, which takes up to three arguments:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">anchor( &lt;anchor-element&gt;? &amp;&amp; &lt;anchor-side&gt;, &lt;length-percentage&gt;? )</code></pre>
<p>So, we’re identifying an anchor element, saying which side we want the target to be positioned on, and how big we want it to be. It’s worth noting that <code>anchor()</code> can only be declared on inset-related properties (e.g. <code>top</code>, <code>left</code>, <code>inset-block-end</code>, etc.)</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
top: anchor(--my-anchor bottom);
left: anchor(--my-anchor end, 50%);
}</code></pre>
<p>Let’s break down the function’s arguments.</p>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;anchor-element&gt;</summary>
<p>This argument specifies which anchor element we want to attach the target to. We can supply it with either the anchor’s name (see <a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-attaching-targets-to-anchors">“Attaching targets to anchors”</a>).</p>
<p>We also have the choice of not supplying an anchor at all. In that case, the target element uses an implicit anchor element defined in <code>position-anchor</code>. If there isn’t an implicit anchor, the function resolves to its fallback. Otherwise, it is invalid and ignored.</p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;anchor-side&gt;</summary>
<p>This argument sets which side of the anchor we want to position the target element to, e.g. the anchor’s <code>top</code>, <code>left</code>, <code>bottom</code>, <code>right</code>, etc.</p>
<p>But we have more options than that, including logical side keywords (<code>inside</code>, <code>outside</code>), logical direction arguments relative to the user’s writing mode (<code>start</code>, <code>end</code>, <code>self-start</code>, <code>self-end</code>) and, of course, <code>center</code>.</p>
<ul class="wp-block-list">
<li><code>&lt;anchor-side&gt;</code>: Resolves to the <code>&lt;length&gt;</code> of the corresponding side of the anchor element. It has physical arguments (<code>top</code>, <code>left</code>, <code>bottom</code> <code>right</code>), logical side arguments (<code>inside</code>, <code>outside</code>), logical direction arguments relative to the user’s writing mode (<code>start</code>, <code>end</code>, <code>self-start</code>, <code>self-end</code>) and the <code>center</code> argument.</li>
<li><code>&lt;percentage&gt;</code>: Refers to the position between the <code>start</code> (<code>0%</code>) and <code>end</code> (<code>100%</code>). Values below <code>0%</code> and above <code>100%</code> are allowed.</li>
</ul>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;length-percentage&gt;</summary>
<p>This argument is totally optional, so you can leave it out if you’d like. Otherwise, use it as a way of re-sizing the target elemenrt whenever it doesn’t have a valid anchor or position. It positions the target to a fixed <code>&lt;length&gt;</code> or <code>&lt;percentage&gt;</code> relative to its containing block.</p>
</details>
<p>Let’s look at examples using different types of arguments because they all do something a <em>little</em> different.</p>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using physical arguments</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380924" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>Physical arguments</strong> (<code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>) can be used to position the target regardless of the user’s writing mode. For example, we can position the <code>right</code> and <code>bottom</code> inset properties of the target at the <code>anchor(top)</code> and <code>anchor(left)</code> sides of the anchor, effectively positioning the target at the anchor’s top-left corner:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
bottom: anchor(top);
right: anchor(left);
}</code></pre>
<p></p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using logical side keywords</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-t ... |
http://localhost:1200/css-tricks/popular/false - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Popular this month</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/popular/false" rel="self" type="application/rss+xml"></atom:link>
<description>Popular CSS articles this month - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Tue, 07 Jan 2025 10:24:40 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>Yet Another Anchor Positioning Quirk</title>
<description><p>I strongly believe Anchor Positioning will go down as one of the greatest additions to CSS. It may not be as game-changing as Flexbox or Grid, but it does fill a positioning gap that has been missing for decades. As awesome as I think it is,&nbsp;<a href="https://css-tricks.com/anchor-positioning-quirks/">CSS Anchor Positioning has a lot of quirks</a>, some of which are the product of its novelty and others due to its unique way of working. Today, I want to bring you yet another Anchor Positioning quirk that has&nbsp;bugged me since I first saw it.</p>
<span id="more-382893"></span>
<h3 class="wp-block-heading" id="the-inception"><a href="https://css-tricks.com/yet-another-anchor-positioning-quirk/#aa-the-inception" aria-hidden="true" class="aal_anchor" id="aa-the-inception"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The inception</h3>
<p>It all started a month ago when I was reading about what other people have made using Anchor Positioning, specifically this post by <a href="https://css-tricks.com/author/afiftemani/">Temani Afif</a> about <a href="https://frontendmasters.com/blog/custom-range-slider-using-anchor-positioning-scroll-driven-animations/" rel="noopener">“Anchor Positioning &amp; Scroll-Driven Animations.”</a> I strongly encourage you to read it and find out what caught my eye there. Combining Anchor Positioning and <a href="https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/">Scroll-Driven Animation</a>, he makes a range slider that changes colors while it progresses.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_JjqNEbZ" src="https://codepen.io/anon/embed/JjqNEbZ?height=450&amp;theme-id=1&amp;slug-hash=JjqNEbZ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed JjqNEbZ" title="CodePen Embed JjqNEbZ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Amazing by itself, but it’s interesting that he is using two target elements with the same anchor name, each attached to its corresponding anchor, just like magic. If this doesn’t seem as interesting as it looks, we should then briefly recap how Anchor Positioning works.</p>
<h3 class="wp-block-heading" id="anchor-positioning-and-the-anchor-scope-property"><a href="https://css-tricks.com/yet-another-anchor-positioning-quirk/#aa-css-anchor-positioning-and-the-anchor-scope-property" aria-hidden="true" class="aal_anchor" id="aa-css-anchor-positioning-and-the-anchor-scope-property"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS Anchor Positioning and the <code>anchor-scope</code> property</h3>
<p class="is-style-explanation">See our complete <a href="https://css-tricks.com/css-anchor-positioning-guide/">CSS Anchor Positioning Guide</a> for a comprehensive deep dive.</p>
<p>Anchor Positioning brings two new concepts to CSS, an <em>anchor</em> element and a <em>target</em> element. The anchor is the element used as a reference for positioning other elements, hence the anchor name. While the target is an absolutely-positioned element placed relative to one or more anchors.</p>
<p>An anchor and a target can be almost every element, so you can think of them as just two <code>div</code> sitting next to each other:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="anchor"&gt;anchor&lt;/div&gt;
&lt;div class="target"&gt;target&lt;/div&gt;</code></pre>
<p>To start, we first have to register the anchor element in CSS using the <a href="https://css-tricks.com/almanac/properties/a/anchor-name/"><code>anchor-name</code></a> property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.anchor {
anchor-name: --my-anchor;
}</code></pre>
<p>And the <a href="https://css-tricks.com/almanac/properties/p/position-anchor/"><code>position-anchor</code></a> property on an absolutely-positioned element attaches it to an anchor of the same name. However, to move the target around the anchor we need the <a href="https://css-tricks.com/almanac/properties/p/position-area/"><code>position-area</code></a> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-anchor: --my-anchor;
position-area: top right;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_oNKavLV" src="https://codepen.io/anon/embed/preview/oNKavLV?height=450&amp;theme-id=1&amp;slug-hash=oNKavLV&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed oNKavLV" title="CodePen Embed oNKavLV" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>This works great, but things get complicated if we change our markup to include more anchors and targets:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;ul&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 1&lt;/div&gt;
&lt;div class="target"&gt;target 1&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 2&lt;/div&gt;
&lt;div class="target"&gt;target 2&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 3&lt;/div&gt;
&lt;div class="target"&gt;target 3&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>Instead of each target attaching to its closest anchor, they all pile up at the last registered anchor in the DOM.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_BagXMNv" src="https://codepen.io/anon/embed/preview/BagXMNv?height=450&amp;theme-id=1&amp;slug-hash=BagXMNv&amp;default-tab=html,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed BagXMNv" title="CodePen Embed BagXMNv" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>The <a href="https://css-tricks.com/almanac/properties/a/anchor-scope/#aa-why-we-need-anchor-scope"><code>anchor-scope</code></a> property was introduced in Chrome 131 as an answer to this issue. It limits the scope of anchors to a subtree so that each target attaches correctly. However, I don’t want to focus on this property, because what initially caught my attention was that <strong>Temani didn’t use it</strong>. For some reason, they all attached correctly, again, like magic.</p>
<h3 class="wp-block-heading" id="what-s-happening-"><a href="https://css-tricks.com/yet-another-anchor-positioning-quirk/#aa-whats-happening" aria-hidden="true" class="aal_anchor" id="aa-whats-happening"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What’s happening?</h3>
<p>Targets usually attach to the last anchor on the DOM instead of their closest anchor, but in our first example, we saw two anchors with the same <code>anchor-name</code> and their corresponding targets attached. All this without the <code>anchor-scope</code> property. What’s happening?</p>
<p>Two words: <strong>Containing Block</strong>.</p>
<p>Something to know about Anchor Positioning is that it relies a lot on how an element’s containing block is built. This isn’t something inherently from Anchor Positioning but from absolute positioning. Absolute elements are positioned relative to their containing block, and inset properties like <code>top: 0px</code>, <code>left: 30px</code> or <code>inset: 1rem</code> are just moving an element around its containing block boundaries, creating what’s called the <strong><a href="https://www.w3.org/TR/css-position-3/#resolving-insets" rel="noopener">inset-modified containing block</a></strong>.</p>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" fetchpriority="high" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1920%2C1080&amp;ssl=1" alt="An element being shrunk by its inset-modified containing block" class="wp-image-382897" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>A target attached to an anchor isn’t any different, and what the <code>position-area</code> property does under the table is change the target’s inset-modified containing block so it is right next to the anchor.</p>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1920%2C1080&amp;ssl=1" alt="A target element inset-modified containing block shrunk to be in the top left corner of an anchor" class="wp-image-382898" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Usually, the containing block of an absolutely-positioned element is the whole viewport, but it can be changed by any ancestor with a position other than <code>static</code> (usually <code>relative</code>). Temani takes advantage of this fact and creates a new containing block for each slider, so they can only be attached to their corresponding anchors. If you snoop around the code, you can find it at the beginning:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">label {
position: relative;
/* No, It's not useless so don't remove it (or remove it and see what happens) */
}</code></pre>
<p>If we use this tactic on our previous examples, suddenly they are all correctly attached!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_zxOvNGE" src="https://codepen.io/anon/embed/preview/zxOvNGE?height=450&amp;theme-id=1&amp;slug-hash=zxOvNGE&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed zxOvNGE" title="CodePen Embed zxOvNGE" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="yet-another-quirk"><a href="https://css-tricks.com/yet-another-anchor-positioning-quirk/#aa-yet-another-quirk" aria-hidden="true" class="aal_anchor" id="aa-yet-another-quirk"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Yet another quirk</h3>
<p>We didn’t need to use the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-scope/">anchor-scope</a></code> property to attach each anchor to its respective target, but instead took advantage of how the containing block of absolute elements is computed. However, there is yet another approach, one that doesn’t need any extra bits of code.</p>
<p>This occurred to me when I was also experimenting with <a href="https://css-tricks.com/popping-comments-with-css-anchor-positioning-and-view-driven-animations/">Scroll-Driven Animations and Anchor Positioning</a> and trying to attach text-bubble footnotes on the side of a post, like the following:</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1920%2C1080&amp;ssl=1" alt="A blog post body with paragraphs, the paragraphs have footnotes attached on the sides" class="wp-image-382899" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Logically, each footnote would be a target, but the choice of an anchor is a little more tricky. I initially thought that each paragraph would work as an anchor, but that would mean having more than one anchor with the same <code>anchor-name</code>. The result: all the targets would pile up at the last anchor:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_jENbBNa" src="https://codepen.io/anon/embed/preview/jENbBNa?height=450&amp;theme-id=1&amp;slug-hash=jENbBNa&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed jENbBNa" title="CodePen Embed jENbBNa" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>This could be solved using our prior approach of creating a new containing block for each note. However, there is another route we can take, what I call the reductionist method. The problem comes when there is more than one anchor with the same <code>anchor-name</code>, so we will reduce the number of anchors to one, using an element that could work as the common anchor for all targets.</p>
<p>In this case, we just want to position each target on the sides of the post so we can use the entire body of the post as an anchor, and since each target is naturally aligned on the vertical axis, what’s left is to move them along the horizontal axis:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_oNKqwgy" src="https://codepen.io/anon/embed/preview/oNKqwgy?height=450&amp;theme-id=1&amp;slug-hash=oNKqwgy&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed oNKqwgy" title="CodePen Embed oNKqwgy" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>You can better check how it was done on the original post!</p>
<h3 class="wp-block-heading" id="conclusion"><a href="https://css-tricks.com/yet-another-anchor-positioning-quirk/#aa-conclusion" aria-hidden="true" class="aal_anchor" id="aa-conclusion"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h3>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="anchor-positioning"></baseline-status>
<p>The <code>anchor-scope</code> may be the most recent CSS property to be shipped to a browser (so far, just in Chrome 131+), so we can’t expect its support to be something out of this world. And while I would love to use it every now and there, it will remain bound to short demos for a while. This isn’t a reason to limit the use of other Anchor Positioning properties, which are supported in Chrome 125 onwards (and let’s hope in other browsers in the near future), so I hope these little quirks can help you to keep using Anchor Positioning without any fear.</p>
</description>
<link>https://css-tricks.com/yet-another-anchor-positioning-quirk/</link>
<guid isPermaLink="false">https://css-tricks.com/yet-another-anchor-positioning-quirk/</guid>
<pubDate>Mon, 09 Dec 2024 16:54:00 GMT</pubDate>
<author>Juan Diego Rodríguez</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2024/12/Yet-Another-Anchor-Positioning-Quirk.png" type="image/jpeg"></enclosure>
<category>anchor positioning</category>
</item>
<item>
<title>Knowing CSS is Mastery to Frontend Development</title>
<description><p><a href="https://helloanselm.com/writings/knowing-css-is-mastery-to-frontend-development" rel="noopener">Anselm Hannemann</a> on the intersection between frameworks and <a href="https://thebasics.dev/" rel="noopener">learning the basics</a>:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Nowadays people can write great React and TypeScript code. Most of the time a component library like MUI, Tailwind and others are used for styling. However, nearly no one is able to judge whether the CSS in the codebase is good or far from optimal. It is magically applied by our toolchain into the HTML and we struggle to understand why the website is getting slower and slower.</p>
</blockquote>
<span id="more-382956"></span>
<p>Related, from <a href="https://infrequently.org/" rel="noopener">Alex Russell</a>:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Many need help orienting themselves as to which end of the telescope is better for examining frontend problems. Frameworkism is now the dominant creed of frontend discourse. It insists that all user problems will be solved if teams just framework&nbsp;<em>hard enough</em>. This is non-sequitur, if not entirely backwards. In practice,&nbsp;<strong>the only thing that makes web experiences good is caring about the user experience</strong>&nbsp;— specifically, the experience of folks at the margins. Technologies come and go, but what always makes the difference is giving a toss about the user.</p>
</blockquote>
<p>
<a href="https://helloanselm.com/writings/knowing-css-is-mastery-to-frontend-development" class="button">
Direct Link →
</a>
</p>
</description>
<link>https://css-tricks.com/knowing-css-is-mastery-to-frontend-development/</link>
<guid isPermaLink="false">https://css-tricks.com/knowing-css-is-mastery-to-frontend-development/</guid>
<author>Geoff Graham</author>
<category>css fundamentals</category>
</item>
<item>
<title>One of Those “Onboarding” UIs, With Anchor Positioning</title>
<description><p>Welcome to “Anchor Positioning 101” where we will be exploring this interesting new CSS feature. Our textbook for this class will be the extensive <a href="https://css-tricks.com/css-anchor-positioning-guide/">“Anchor Positioning Guide”</a> that <a href="https://css-tricks.com/author/monknow/" data-type="link" data-id="https://css-tricks.com/author/monknow/">Juan Diego Rodriguez</a> published here on CSS-Tricks.</p>
<p>I’m excited for this one. Some of you may remember when CSS-Tricks released the <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">“Flexbox Layout Guide”</a> or the <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">“Grid Layout Guide”</a> — I certainly do and still have them both bookmarked! I spend a lot of time flipping between tabs to make sure I have the right syntax in my “experimental” CodePens.</p>
<p>I’ve been experimenting with CSS anchor positioning like the “good old days” since Juan published his guide, so I figured it’d be fun to share some of the excitement, learn a bit, experiment, and of course: <em>build stuff!</em></p>
<span id="more-382731"></span>
<h3 class="wp-block-heading" id="css-anchor-positioning-introduction"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-css-anchor-positioning-introduction" aria-hidden="true" class="aal_anchor" id="aa-css-anchor-positioning-introduction"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>CSS Anchor Positioning introduction</h3>
<p>Anchor positioning lets us attach — or “anchor” — one element to one or more other elements. More than that, it allows us to define <em>how</em> a “target” element (that’s what we call the element we’re attaching to an anchor element) is positioned next to the anchor-positioned element, including <em>fallback positioning</em> in the form of a new <code><a href="https://css-tricks.com/almanac/rules/p/position-try/">@position-try</a></code> at-rule.</p>
<p>The most hand-wavy way to explain the benefits of anchor positioning is to think of it as a powerful enhancement to <code>position: absolute;</code> as it helps absolutely-positioned elements <strong>do what you expect</strong>. Don’t worry, we’ll see how this works as we go.</p>
<p>Anchor positioning is currently a <a href="https://drafts.csswg.org/css-anchor-position/" rel="noopener">W3C draft spec</a>, so you know it’s fresh. It’s marked as “limited availability” in Baseline which at the time of writing means it is limited to Chromium-based browsers (versions 125+). That said, the considerate folks over at <a href="https://www.oddbird.net/" rel="noopener">Oddbird</a> have a <a href="https://anchor-polyfill.netlify.app/" rel="noopener">polyfill available</a> that’ll help out other browsers until they ship support.</p>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="anchor-positioning"></baseline-status>
<div class="caniuse"><div class="caniuse-header"><p>This browser support data is from <a href="http://caniuse.com/#feat=css-anchor-positioning" rel="noopener">Caniuse</a>, which has more detail. A number indicates that browser supports the feature at that version and up.</p></div><div class="caniuse-section"><h4>Desktop</h4><table class="browser-support-table"><thead><tr><th class="chrome"><span>Chrome</span></th><th class="firefox"><span>Firefox</span></th><th class="ie"><span>IE</span></th><th class="edge"><span>Edge</span></th><th class="safari"><span>Safari</span></th></tr></thead><tbody><tr><td class="y yep" title="Chrome - "><span class="caniuse-agents-version version">125</span></td><td class="n nope" title="Firefox - "><span class="caniuse-agents-version version">No</span></td><td class="n nope" title="IE - "><span class="caniuse-agents-version version">No</span></td><td class="y yep" title="Edge - "><span class="caniuse-agents-version version">125</span></td><td class="n nope" title="Safari - "><span class="caniuse-agents-version version">No</span></td></tr></tbody></table></div><div class="caniuse-section"><h4>Mobile / Tablet</h4><table class="browser-support-table"><thead><tr><th class="and_chr"><span>Android Chrome</span></th><th class="and_ff"><span>Android Firefox</span></th><th class="android"><span>Android</span></th><th class="ios_saf"><span>iOS Safari</span></th></tr></thead><tbody><tr><td class="y yep" title="Android Chrome - "><span class="caniuse-agents-version version">131</span></td><td class="n nope" title="Android Firefox - "><span class="caniuse-agents-version version">No</span></td><td class="y yep" title="Android - "><span class="caniuse-agents-version version">131</span></td><td class="n nope" title="iOS Safari - "><span class="caniuse-agents-version version">No</span></td></tr></tbody></table></div></div>
<p class="is-style-explanation">Oddbird contributes polyfills for <em>many</em> new CSS features and you (yes, you!) can support their work on <a href="https://github.com/sponsors/oddbird" rel="noopener">Github</a> or <a href="https://opencollective.com/oddbird-open-source" rel="noopener">Open Collective</a>!</p>
<p><a href="https://xanthir.com/contact/" rel="noopener">Tab Atkins-Bittner</a>, contributing author to the W3C draft spec on anchor positioning, spoke on the topic at CSS Day 2024. The full conference talk is available on YouTube:</p>
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe data-video-id="p18LhnYNkDQ?feature=oembed" class="br-lazy" data-breeze="https://www.youtube.com/embed/p18LhnYNkDQ?feature=oembed" title="Anchor Positioning | Tab Atkins-Bittner | CSS Day 2024" width="500" height="281" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="no-referrer" allowfullscreen=""></iframe>
</div></figure>
<p>Here at CSS-Tricks, Juan demonstrated how to mix and match <a href="https://css-tricks.com/popping-comments-with-css-anchor-positioning-and-view-driven-animations/">anchor positioning with view-driven animations</a> for an awesome floating notes effect:</p>
<figure class="wp-block-video"><video controls="" src="https://css-tricks.com/wp-content/plugins/breeze/assets/images/placeholder.mp4" data-breeze="https://css-tricks.com/wp-content/uploads/2024/11/anchor-view-driven-animation.mov" playsinline="" class="br-lazy"></video></figure>
<p>Front-end friend <a href="https://www.kevinpowell.co/" rel="noopener">Kevin Powell</a> recently released a video demonstrating how <a href="https://www.youtube.com/watch?v=DNXEORSk4GU" rel="noopener">“CSS Popover + Anchor Positioning is Magical”</a>.</p>
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe data-video-id="DNXEORSk4GU?feature=oembed" class="br-lazy" data-breeze="https://www.youtube.com/embed/DNXEORSk4GU?feature=oembed" title="CSS Popover + Anchor Positioning is Magical" width="500" height="281" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="no-referrer" allowfullscreen=""></iframe>
</div></figure>
<p>And finally, in the tradition of “making fun games to learn CSS,” <a href="https://thomaspark.co/" rel="noopener">Thomas Park</a> released <a href="https://anchoreum.com/" rel="noopener">Anchoreum</a> (a “<a href="https://flexboxfroggy.com/" rel="noopener">Flexbox Froggy</a>“-type game) to learn about CSS anchor positioning. Highly recommend checking this out to get the hang of the <code><a href="https://css-tricks.com/almanac/properties/p/position-area/">position-area</a></code> property!</p>
<h3 class="wp-block-heading" id="the-homework"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-the-homework" aria-hidden="true" class="aal_anchor" id="aa-the-homework"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The homework</h3>
<p>OK, now that we’re caught up on what CSS anchor positioning <em>is</em> and the excitement surrounding it, let’s talk about what it <em>does</em>. Tethering an element to another element? That has a <strong>lot</strong> of potential. Quite a few instances I can remember where I’ve had to fight with <code>absolute</code> positioning and <code>z-index</code> in order to get something positioned <em>just right</em>.</p>
<p>Let’s take a quick look at the basic syntax. First, we need two elements, an anchor-positioned element and the target element that will be tethered to it.</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;!-- Anchor element --&gt;
&lt;div id="anchor"&gt;
Anchor
&lt;/div&gt;
&lt;!-- Target element --&gt;
&lt;div id="target"&gt;
Target
&lt;/div&gt;</code></pre>
<p>We set an element as an anchor-positioned element by providing it with an <a href="https://css-tricks.com/almanac/properties/a/anchor-name/"><code>anchor-name</code></a>. This is a unique name of our choosing, however it needs the double-dash prefix, like <a href="https://css-tricks.com/a-complete-guide-to-custom-properties/">CSS custom properties</a>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">#anchor {
anchor-name: --anchor;
}</code></pre>
<p>As for our target element, we’ll need to set <code>position: absolute;</code> on it as well as tell the element what anchor to tether to. We do that with a new CSS property, <a href="https://css-tricks.com/almanac/properties/p/position-anchor/"><code>position-anchor</code></a> using a value that matches the <code>anchor-name</code> of our anchor-positioned element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="6,7"><code markup="tt">#anchor {
anchor-name: --anchor;
}
#target {
position: absolute;
position-anchor: --anchor;
}</code></pre>
<p>May not look like it yet, but now our two elements are attached. We can set the <em>actual</em> positioning on the target element by providing a <a href="https://css-tricks.com/almanac/properties/p/position-area/"><code>position-area</code></a>. To position our target element, <code>position-area</code> creates an invisible 3×3 grid over the anchor-positioned element. <a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-positioning-targets">Using positioning keywords</a>, we can designate where the target element appears near the anchor-positioned element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="4"><code markup="tt">#target {
position: absolute;
position-anchor: --anchor;
position-area: top center;
}</code></pre>
<p>Now we see that our target element is anchored to the top-center of our anchor-positioned element!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_VwooOeO/32f4f325746dfffca524a670c3dd61f0" src="https://codepen.io/anon/embed/preview/VwooOeO/32f4f325746dfffca524a670c3dd61f0?height=450&amp;theme-id=1&amp;slug-hash=VwooOeO/32f4f325746dfffca524a670c3dd61f0&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed VwooOeO/32f4f325746dfffca524a670c3dd61f0" title="CodePen Embed VwooOeO/32f4f325746dfffca524a670c3dd61f0" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="705" height="453" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/basic-anchor.png?resize=705%2C453&amp;ssl=1" alt="red rectangle labelled &quot;target&quot; attached to the top of a blue square labelled &quot;Anchor&quot;" class="wp-image-382749" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/basic-anchor.png?w=705&amp;ssl=1 705w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/basic-anchor.png?resize=300%2C193&amp;ssl=1 300w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="anchoring-pseudoelements"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-anchoring-pseudo-elements" aria-hidden="true" class="aal_anchor" id="aa-anchoring-pseudo-elements"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Anchoring pseudo-elements</h4>
<p>While playing with anchor positioning, I noticed you can anchor pseudo-elements, just the same as any other element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">#anchor {
anchor-name: --anchor;
&amp;::before {
content: "Target";
position: absolute;
position-anchor: --anchor;
left: anchor(center);
bottom: anchor(center);
}
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_xxvPoNb/7f49823ffe8497f2e9b4e91974beeb61" src="https://codepen.io/anon/embed/preview/xxvPoNb/7f49823ffe8497f2e9b4e91974beeb61?height=450&amp;theme-id=1&amp;slug-hash=xxvPoNb/7f49823ffe8497f2e9b4e91974beeb61&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed xxvPoNb/7f49823ffe8497f2e9b4e91974beeb61" title="CodePen Embed xxvPoNb/7f49823ffe8497f2e9b4e91974beeb61" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1470" height="758" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/anchor-pseudo.png?resize=1470%2C758&amp;ssl=1" alt="a semi-transparent red square labelled &quot;Target&quot; is attached to the upper corner of a blue square labelled &quot;Anchor&quot;" class="wp-image-382751" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/anchor-pseudo.png?w=1470&amp;ssl=1 1470w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/anchor-pseudo.png?resize=300%2C155&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/anchor-pseudo.png?resize=1024%2C528&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/11/anchor-pseudo.png?resize=768%2C396&amp;ssl=1 768w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Might be useful for adding design flourishes to elements or adding functionality as some sort of indicator.</p>
<h4 class="wp-block-heading" id="moving-anchors"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-moving-anchors" aria-hidden="true" class="aal_anchor" id="aa-moving-anchors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Moving anchors</h4>
<p>Another quick experiment was to see if we can <em>move</em> anchors. And it turns out this is possible!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_LYwzKep/c5383e79dee9fa01f5c60db011959319" src="https://codepen.io/anon/embed/LYwzKep/c5383e79dee9fa01f5c60db011959319?height=450&amp;theme-id=1&amp;slug-hash=LYwzKep/c5383e79dee9fa01f5c60db011959319&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed LYwzKep/c5383e79dee9fa01f5c60db011959319" title="CodePen Embed LYwzKep/c5383e79dee9fa01f5c60db011959319" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<figure class="wp-block-video"><video controls="" src="https://css-tricks.com/wp-content/plugins/breeze/assets/images/placeholder.mp4" data-breeze="https://css-tricks.com/wp-content/uploads/2024/11/moving-anchor-hover.mov" class="br-lazy"></video></figure>
<p>Notice the use of <a href="https://css-tricks.com/almanac/functions/a/anchor/"><code>anchor()</code></a> functions instead of <code>position-area</code> to position the target element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">#target {
position: absolute;
position-anchor: --anchor-one;
top: anchor(bottom);
left: anchor(left);
}</code></pre>
<p><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor-functions">CSS anchor functions</a> are an alternate way to position target elements based on the computed values of the anchor-positioned element itself. Here we are setting the target element’s top property value to match the anchor-positioned element’s bottom value. Similarly, we can set the target’s <code>left</code> property value to match the anchor-positioned element’s <code>left</code> value.</p>
<p>Hovering over the container element swaps the <code>position-anchor</code> from <code>--anchor-one</code> to <code>--anchor-two</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.container:hover {
#target {
position-anchor: --anchor-two;
}
}</code></pre>
<p> We are also able to set a <code>transition</code> as we position the target using <code>top</code> and <code>left</code>, which makes it swap smoothly between anchors.</p>
<h4 class="wp-block-heading" id="extra-experimental"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-extra-experimental" aria-hidden="true" class="aal_anchor" id="aa-extra-experimental"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Extra experimental</h4>
<p>Along with being the first to release CSS anchor-positioning, the Chrome dev team recently released new pseudo-selectors related to the <code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> elements. The <code><a href="https://developer.chrome.com/blog/styling-details" data-type="link" data-id="https://developer.chrome.com/blog/styling-details" rel="noopener">::details-content</a></code> pseudo-selector allows you to style the “hidden” part of the <code>&lt;details&gt;</code> element. </p>
<p>With this information, I thought: “<em>can I anchor it?</em>” and sure enough, you can!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_ZYzzqOJ/676e5968b2726fb2c3383819ffb8d15b" src="https://codepen.io/anon/embed/ZYzzqOJ/676e5968b2726fb2c3383819ffb8d15b?height=450&amp;theme-id=1&amp;slug-hash=ZYzzqOJ/676e5968b2726fb2c3383819ffb8d15b&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed ZYzzqOJ/676e5968b2726fb2c3383819ffb8d15b" title="CodePen Embed ZYzzqOJ/676e5968b2726fb2c3383819ffb8d15b" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Again, this is <em>defin</em>itely<em> not</em> ready for prime-time, but it’s always fun to experiment!</p>
<h3 class="wp-block-heading" id="practical-examinations"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-practical-examinations" aria-hidden="true" class="aal_anchor" id="aa-practical-examinations"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Practical examinations</h3>
<p>Let’s take this a bit further and tackle more practical challenges using CSS anchor positioning. Please keep in mind that all these examples are <strong>Chrome-only</strong> at the time of writing!</p>
<h4 class="wp-block-heading" id="tooltips"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-tooltips" aria-hidden="true" class="aal_anchor" id="aa-tooltips"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Tooltips</h4>
<p>One of the most straightforward use cases for CSS anchor positioning is possibly a tooltip. Makes a lot of sense: hover over an icon and a label floats nearby to explain what the icon does. I didn’t quite want to make yet another tutorial on how to make a tooltip and luckily for me, Zell Liew recently wrote an article on tooltip best practices, so we can focus purely on anchor positioning and refer to Zell’s work for the semantics.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_zYgXEgo/4937f21370de0a7ebf1fca1d6166d5c8" src="https://codepen.io/anon/embed/preview/zYgXEgo/4937f21370de0a7ebf1fca1d6166d5c8?height=450&amp;theme-id=1&amp;slug-hash=zYgXEgo/4937f21370de0a7ebf1fca1d6166d5c8&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed zYgXEgo/4937f21370de0a7ebf1fca1d6166d5c8" title="CodePen Embed zYgXEgo/4937f21370de0a7ebf1fca1d6166d5c8" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<figure class="wp-block-video"><video controls="" src="https://css-tricks.com/wp-content/plugins/breeze/assets/images/placeholder.mp4" data-breeze="https://css-tricks.com/wp-content/uploads/2024/11/anchor-tooltip-hover.mov" class="br-lazy"></video></figure>
<p>Now, let’s check out one of these tooltips:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;!-- ... --&gt;;
&lt;li class="toolbar-item"&gt;;
&lt;button type="button"
id="inbox-tool"
aria-labelledby="inbox-label"
class="tool"&gt;
&lt;svg id="inbox-tool-icon"&gt;
&lt;!-- SVG icon code ... --&gt;
&lt;/svg&gt;
&lt;/button&gt;
&lt;div id="inbox-label" role="tooltip"&gt;
&lt;p&gt;Inbox&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;!-- ... --&gt;</code></pre>
<p>The HTML is structured in a way where the tooltip element is a sibling of our anchor-positioned <code>&lt;button&gt;</code>, notice how it has the <code>[aria-labelledby]</code> attribute set to match the tooltip’s <code>[id]</code>. The tooltip itself is a generic <code>&lt;div&gt;</code>, semantically enhanced to become a tooltip with the <code>[role="tooltip"]</code> attribute. We can also use <code>[role="tooltip"]</code> as a <a href="https://benmyers.dev/blog/semantic-selectors/" rel="noopener">semantic selector</a> to add common styles to tooltips, including the tooltip’s positioning relative to its anchor.</p>
<p>First, let’s turn our button into an anchored element by giving it an <code>anchor-name</code>. Next, we can set the target element’s <code>position-anchor</code> to match the <code>anchor-name</code> of the anchored element. By default, we can set the tooltip’s <code>visibility</code> to <code>hidden</code>, then using CSS sibling selectors, if the target element receives <code>hover</code> or <code>focus-visible</code>, we can then swap the <code>visibility</code> to <code>visible</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Anchor-positioned Element */
#inbox-tool {
anchor-name: --inbox-tool;
}
/* Target element */
[role="tooltip"]#inbox-label {
position-anchor: --inbox-tool
}
/* Target positioning */
[role="tooltip"] {
position: absolute;
position-area: end center;
/* Hidden by default */
visibility: hidden;
}
/* Visible when tool is hovered or receives focus */
.tool:hover + [role="tooltip"],
.tool:focus-visible + [role="tooltip"] {
visibility: visible;
}</code></pre>
<p><em>Ta-da!</em> Here we have a working, CSS anchor-positioned tooltip!</p>
<p class="is-style-explanation">As users of touch devices aren’t able to hover over elements, you may want to <a href="https://css-tricks.com/tooltip-best-practices/#aa-tooltip-limitations-and-alternatives">explore toggletips</a> instead!</p>
<h4 class="wp-block-heading" id="floating-disclosures"><a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/#aa-floating-disclosures" aria-hidden="true" class="aal_anchor" id="aa-floating-disclosures"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Floating disclosures</h4>
<p>Disclosures are another common component pattern that might be a perfect use case for anchor positioning. Disclosures are typically a component where interacting with a toggle will open and close a corresponding element. Think of the good ol’ <a href="https://css-tricks.com/exploring-what-the-details-and-summary-elements-can-do/"><code>&lt;detail&gt;/&lt;summary&gt;</code> HTML element duo</a>, for example.</p>
<p>Currently, if you are looking to create a disclosure-like component which floats over other portions of your user interface, you might be in for some JavaScript, <code>absolute</code> positioning, and <code>z-index</code> related troubles. Soon enough though, we’ll be able to combine CSS anchor positioning with another newer platform feature <code>[popover]</code> to create some incredibly straightforward (and semantically accurate) floating disclosure elements.</p>
<p><a href="https://css-tricks.com/poppin-in/">The Popover API</a> provides a non-modal way to elevate elements to the <code>top-layer</code>, while also baking in some great functionality, such as light dismissals.</p>
<p class="is-style-explanation">Zell also has more information <a href="https://css-tricks.com/clarifying-the-relationship-between-popovers-and-dialogs/">on popovers, dialogs, and modality</a>!</p>
<p>One of the more common patterns you might consider as a “floating disclosure”-type component is a dropdown menu. Here is the HTML we’ll work with:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;nav&gt;
&lt;button id="anchor"&gt;Toggle&lt;/button&gt;
&lt;ul id="target"&gt;
&lt;li&gt;&lt;a href="#"&gt;Link 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#"&gt;Link 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#"&gt;Link 3& ... |
http://localhost:1200/css-tricks/fresh - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Fresh From the Almanac</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/fresh" rel="self" type="application/rss+xml"></atom:link>
<description>Properties, selectors, rules, and functions! - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Tue, 07 Jan 2025 10:24:42 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>prefers-reduced-motion</title>
<description><p>The <code>prefers-reduced-motion</code> feature is used in <a href="https://css-tricks.com/a-complete-guide-to-css-media-queries/">CSS media queries</a> to determine a user’s operating system preferences for animations and transitions on the web. For example, we can determine if the user’s preference is set to “reduced” motion and either eliminate or reduce the movement accordingly.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@media screen and (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}</code></pre>
<span id="more-383264"></span>
<p>If we are using <a href="https://css-tricks.com/css-cascade-layers/">Cascade Layers</a> to prioritize the specificity order of our styles, then we can get rid of those <code>!important</code> keywords by making sure that the styles are in a high-priority layer:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@layer base, components, animation;
@layer animation {
@media screen and (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}
}
@layer components {
/* styles */
}
@layer base {
/* styles */
}</code></pre>
<p>This is CSS that attempts to obliterate any motion on a website under the condition that the user has specified a preference for reduced motion in the accessibility preferences of their operating system.</p>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" fetchpriority="high" decoding="async" width="1654" height="1368" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?resize=1654%2C1368&amp;ssl=1" alt="MacOS settings for reduce motion preferences, set to reduced motion." class="wp-image-383265" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?w=1654&amp;ssl=1 1654w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?resize=300%2C248&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?resize=1024%2C847&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?resize=768%2C635&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/Screenshot-2024-12-18-at-8.21.29%E2%80%AFAM.png?resize=1536%2C1270&amp;ssl=1 1536w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h3 class="wp-block-heading" id="syntax"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-syntax" aria-hidden="true" class="aal_anchor" id="aa-syntax"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Syntax</h3>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Applies styles when Reduced Motion is enabled */
@media screen and (prefers-reduced-motion: reduce) { }
@media screen and (prefers-reduced-motion) { }</code></pre>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>For:</strong> <code>@media</code></li>
<li><strong>Values:</strong> <code>no-preference</code> | <code>reduce</code></li>
<li><strong>Type:</strong> discrete</li>
</ul>
<p>A browser will parse this code and apply it to your site, letting you provide an alternative experience for users who have the Reduced Motion option enabled in their operating system preferences.&nbsp;</p>
<p>It’s worth noting that&nbsp;<code>(prefers-reduced-motion)</code>&nbsp;without the&nbsp;<code>reduce</code>&nbsp;keyword will be evaluated as true. However, it’s better to be explicit in these sorts of circumstances, especially for newer and more obscure features.</p>
<p>You can also target the inverse:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Applies styles when the user has made no preference known */
@media screen and (prefers-reduced-motion: no-preference) { }</code></pre>
<p>Think of this media query&nbsp;<a href="https://css-tricks.com/almanac/rules/s/supports/">like&nbsp;<code>@supports</code></a>: describe the initial appearance, then modify the styles based on capability.</p>
<h3 class="wp-block-heading" id="values"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-values" aria-hidden="true" class="aal_anchor" id="aa-values"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Values</h3>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Applies styles when the user has made no preference known */
@media screen and (prefers-reduced-motion: no-preference) { }
/* Applies styles when Reduced Motion is enabled */
@media screen and (prefers-reduced-motion: reduce) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>no-preference</code>:</strong> Indicates that the user has made no preference known to the system.</li>
<li><strong><code>reduce</code>:</strong> Indicates that user has notified the system that they prefer an interface that minimizes the amount of movement or animation, preferably to the point where all non-essential movement is removed.</li>
</ul>
<h3 class="wp-block-heading" id="testing-reduced-motion-preferences"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-testing-reduced-motion-preferences" aria-hidden="true" class="aal_anchor" id="aa-testing-reduced-motion-preferences"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Testing reduced motion preferences</h3>
<p>Provided you’re up to date with MacOS, you should be able to check it out in Safari. Go to <strong>System Preferences</strong>, select the <strong>Accessibility</strong> category, select the <strong>Display</strong> tab, and enable the <strong>Reduce Motion</strong> option. You’ll see that the example animation in the CodePen example below updates when the checkbox is toggled: the pulsing circle is changed to an inert square:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_PWJPrW" src="https://codepen.io/anon/embed/preview/PWJPrW?height=450&amp;theme-id=1&amp;slug-hash=PWJPrW&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed PWJPrW" title="CodePen Embed PWJPrW" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Here’s a quick video if you don’t have access to this:</p>
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe data-video-id="uANmA7korfs?feature=oembed" class="br-lazy" data-breeze="https://www.youtube.com/embed/uANmA7korfs?feature=oembed" title="Reduced Motion Media Query Example" width="500" height="281" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="no-referrer" allowfullscreen=""></iframe>
</div></figure>
<h3 class="wp-block-heading" id="why-prefers-reduced-motion-matters"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-why-prefers-reduced-motion-matters" aria-hidden="true" class="aal_anchor" id="aa-why-prefers-reduced-motion-matters"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Why <code>prefers-reduced-motion</code> matters</h3>
<p>The reason this setting exists is that on-screen movement is an accessibility concern.&nbsp;<a href="https://css-tricks.com/introduction-reduced-motion-media-query/">Here’s Eric Bailey</a>:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="http://a11yproject.com/posts/understanding-vestibular-disorders/" rel="noopener">Vestibular disorders</a>&nbsp;can cause your vestibular system to struggle to make sense of what is happening, resulting in loss of balance and vertigo, migraines, nausea, and hearing loss. Anyone who has spun around too quickly is familiar with a confused vestibular system.</p>
<p>Vestibular disorders can be caused by both genetic and environmental factors. It’s part of the larger&nbsp;<a href="http://webaim.org/intro/" rel="noopener">spectrum of conditions</a>&nbsp;that make up accessibility concerns and it affects more than&nbsp;<a href="http://vestibular.org/understanding-vestibular-disorder" rel="noopener">70 million people</a>.</p>
</blockquote>
<p>Here he is again in&nbsp;<a href="https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/">a follow-up article</a>:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>If you have a vestibular disorder or have certain kinds of migraine or seizure triggers,&nbsp;<a href="https://source.opennews.org/articles/motion-sick/" rel="noopener">navigating the web can be a lot like walking through a minefield</a>&nbsp;— you’re perpetually one click away from activating an unannounced animation. And that’s just for casual browsing.</p>
</blockquote>
<h3 class="wp-block-heading" id="reduced-motion-vs-nuked-motion"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-reduced-motion-vs-nuked-motion" aria-hidden="true" class="aal_anchor" id="aa-reduced-motion-vs-nuked-motion"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Reduced motion vs. nuked motion</h3>
<p>Knowing this, the temptation might be high to go nuclear on the motion and wipe it out entirely when a user has specified a reduced motion preference. The trouble with that is — to quote Eric again — “animation isn’t unnecessary.” Some of it might be, but animation can also&nbsp;<em>help</em>&nbsp;accessibility. For example, a&nbsp;<a href="https://css-tricks.com/transitional-interfaces-coded/">“transitional interface”</a>&nbsp;(e.g. a list that animates an opening for a new item to slide into it) can be very helpful.</p>
<p>In this case, perhaps less, slower, or removed&nbsp;<em>motion</em>&nbsp;while leaning harder on color and fading transitions.&nbsp;</p>
<p>Ban Nadel wrote&nbsp;<a href="https://www.bennadel.com/blog/4132-applying-multiple-animation-keyframes-to-support-prefers-reduced-motion-in-css.htm" rel="noopener">“Applying Multiple Animation @keyframes To Support Prefers-Reduced-Motion In CSS”</a>&nbsp;and covered a similar example demonstrating a modal entrance animation that uses both a fade-in and scale-in effect by default. Then, in a&nbsp;<code>prefers-reduced-motion</code>&nbsp;scenario, it uses the fade-in but not the scaling. The scaling causes movement in a way the fading doesn’t.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/*
By default, we'll use the REDUCED MOTION version of the animation.
*/
@keyframes modal-enter {
from {
opacity: 0 ;
}
to {
opacity: 1 ;
}
}
/*
Then, if the user has NO PREFERENCE for motion, we can OVERRIDE the
animation definition to include both the motion and non-motion properties.
*/
@media ( prefers-reduced-motion: no-preference ) {
@keyframes modal-enter {
from {
opacity: 0 ;
transform: scale(0.7) ;
}
to {
opacity: 1 ;
transform: scale(1.0) ;
}
}
}</code></pre>
<h3 class="wp-block-heading" id="browser-support"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-browser-support" aria-hidden="true" class="aal_anchor" id="aa-browser-support"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h3>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="prefers-reduced-motion"></baseline-status>
<h3 class="wp-block-heading" id="the-people-affected"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-specification" aria-hidden="true" class="aal_anchor" id="aa-specification"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Specification</h3>
<p>The <code>prefers-reduced-motion</code> feature is defined in the <a href="https://www.w3.org/TR/mediaqueries-5/#prefers-reduced-motion" rel="noopener">Media Queries Module Level 5 specification</a>. Even it is widely supported by browsers, the specification is in Working Draft status at the time of writing, meaning the information can change between now and when it becomes a formal Candidate Recommendation.</p>
<h3 class="wp-block-heading" id="related-guides"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-related-guides" aria-hidden="true" class="aal_anchor" id="aa-related-guides"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Related guides</h3>
<div class="in-article-cards">
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2020-10-02" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Dec 19, 2024 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-css-media-queries-guide" aria-hidden="true" class="aal_anchor" id="aa-css-media-queries-guide"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/a-complete-guide-to-css-media-queries/">
CSS Media Queries Guide </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/agalante/" aria-label="Author page of Andrés Galante">
<img data-recalc-dims="1" loading="lazy" decoding="async" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://i0.wp.com/css-tricks.com/wp-content/cache/breeze-extra/gravatars/Ando1-80x80.jpg?resize=80%2C80&amp;ssl=1" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/agalante/">
Andrés Galante </a>
</div>
</article>
</div>
<h3 class="wp-block-heading" id="related-tricks"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-related-tricks" aria-hidden="true" class="aal_anchor" id="aa-related-tricks"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Related tricks!</h3>
<div class="in-article-cards">
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2020-11-03" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Nov 3, 2020 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-gifs-and-prefers-reduced-motion" aria-hidden="true" class="aal_anchor" id="aa-gifs-and-prefers-reduced-motion"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/gifs-and-prefers-reduced-motion/">
GIFS and prefers-reduced-motion </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="in-article-card links" id="mini-post-383264">
<time datetime="2019-05-31" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
May 31, 2019 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-reducing-motion-with-the-picture-element" aria-hidden="true" class="aal_anchor" id="aa-reducing-motion-with-the-picture-element"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/reducing-motion-with-the-picture-element/">
Reducing motion with the picture element </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/robinrendle/" aria-label="Author page of Robin Rendle">
<img data-recalc-dims="1" loading="lazy" decoding="async" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://i0.wp.com/css-tricks.com/wp-content/cache/breeze-extra/gravatars/me-black-white-80x80.jpg?resize=80%2C80&amp;ssl=1" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/robinrendle/">
Robin Rendle </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2019-06-21" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Jun 21, 2019 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-reduced-motion-picture-technique-take-two" aria-hidden="true" class="aal_anchor" id="aa-reduced-motion-picture-technique-take-two"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/reduced-motion-picture-technique-take-two/">
Reduced Motion Picture Technique, Take Two </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2017-04-14" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Apr 14, 2017 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-smooth-scrolling-and-accessibility" aria-hidden="true" class="aal_anchor" id="aa-smooth-scrolling-and-accessibility"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/smooth-scrolling-accessibility/">
Smooth Scrolling and Accessibility </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/heathermig/" aria-label="Author page of Heather Migliorisi">
<img data-recalc-dims="1" loading="lazy" decoding="async" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://i0.wp.com/css-tricks.com/wp-content/cache/breeze-extra/gravatars/hmig-80x80.jpg?resize=80%2C80&amp;ssl=1" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/heathermig/">
Heather Migliorisi </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2022-02-23" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Feb 23, 2022 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-5-accessibility-quick-wins-you-can-implement-today" aria-hidden="true" class="aal_anchor" id="aa-5-accessibility-quick-wins-you-can-implement-today"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/5-accessibility-quick-wins-you-can-implement-today/">
5 Accessibility Quick Wins You Can Implement Today </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/danyuschick/" aria-label="Author page of Daniel Yuschick">
<img data-recalc-dims="1" loading="lazy" decoding="async" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://i0.wp.com/css-tricks.com/wp-content/cache/breeze-extra/gravatars/EF3E5D0F-F08E-4FA2-8490-E9F2A561A0DA-80x80.jpeg?resize=80%2C80&amp;ssl=1" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/danyuschick/">
Daniel Yuschick </a>
</div>
</article>
</div>
<h3 class="wp-block-heading" id="references"><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-references" aria-hidden="true" class="aal_anchor" id="aa-references"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>References</h3>
<div class="in-article-cards">
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2017-02-10" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Apr 24, 2019 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-an-introduction-to-the-reduced-motion-media-query" aria-hidden="true" class="aal_anchor" id="aa-an-introduction-to-the-reduced-motion-media-query"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/introduction-reduced-motion-media-query/">
An Introduction to the Reduced Motion Media Query </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/ericwbailey/" aria-label="Author page of Eric Bailey">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/188a9d4deb76ac6e69c7f65358897476" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/188a9d4deb76ac6e69c7f65358897476 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/ericwbailey/">
Eric Bailey </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2022-02-08" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Feb 8, 2022 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-no-motion-isnt-always-prefers-reduced-motion" aria-hidden="true" class="aal_anchor" id="aa-no-motion-isnt-always-prefers-reduced-motion"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/nuking-motion-with-prefers-reduced-motion/">
No Motion Isn’t Always prefers-reduced-motion </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/chriscoyier/" aria-label="Author page of Chris Coyier">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/8081b26e05bb4354f7d65ffc34cbbd67 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/chriscoyier/">
Chris Coyier </a>
</div>
</article>
<article class="in-article-card 2021-end-of-year-thoughts" id="mini-post-383264">
<time datetime="2021-12-29" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Jan 18, 2022 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-empathetic-animation" aria-hidden="true" class="aal_anchor" id="aa-empathetic-animation"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/empathetic-animation/">
Empathetic Animation </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/cassieevans/" aria-label="Author page of Cassie Evans">
<img data-recalc-dims="1" loading="lazy" decoding="async" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://i0.wp.com/css-tricks.com/wp-content/cache/breeze-extra/gravatars/rZKsmX4T_400x400-80x80.jpg?resize=80%2C80&amp;ssl=1" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/cassieevans/">
Cassie Evans </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2020-12-16" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Dec 16, 2020 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-slow-movement" aria-hidden="true" class="aal_anchor" id="aa-slow-movement"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/slow-movement/">
Slow Movement </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/mmatuzo/" aria-label="Author page of Manuel Matuzovic">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/fee3aee3642c55f15adfcbeab11e6bb6" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/fee3aee3642c55f15adfcbeab11e6bb6 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/mmatuzo/">
Manuel Matuzovic </a>
</div>
</article>
<article class="in-article-card articles" id="mini-post-383264">
<time datetime="2020-09-22" title="Originally published Dec 20, 2024">
<strong>
Article
</strong>
on
Sep 22, 2020 </time>
<h3><a href="https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/#aa-accessible-web-animation-the-wcag-on-animation-explained" aria-hidden="true" class="aal_anchor" id="aa-accessible-web-animation-the-wcag-on-animation-explained"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>
<a href="https://css-tricks.com/accessible-web-animation-the-wcag-on-animation-explained/">
Accessible Web Animation: The WCAG on Animation Explained </a>
</h3>
<div class="author-row">
<a href="https://css-tricks.com/author/valhead/" aria-label="Author page of Val Head">
<img loading="lazy" alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/48544d7b14d3544427909d5ddb330e76" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/48544d7b14d3544427909d5ddb330e76 2x" class="avatar avatar-80 photo" height="80" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/valhead/">
Val Head </a>
</div>
</article>
</div>
<h3 id="related-posts">Related</h3>
<div class="in-article-cards">
<article class="in-article-card " id="mini-post-13714">
<time datetime="2024-09-09" title="Originally published Sep 9, 2024">
<strong>
Almanac
</strong>
on
Sep 19, 2024 </time>
<h3>
<a href="https://css-tricks.com/almanac/properties/a/animation/">
animation </a>
</h3>
<a href="https://css-tricks.com/almanac/properties/a/animation/" class="almanac-example">
<code class="language-css">.element { animation: pulse 5s infinite; }</code>
</a>
<div class="tags">
<a href="https://css-tricks.com/tag/animation/" rel="tag">animation</a> </div>
<div class="author-row">
<a href="https://css-tricks.com/author/ryantrimble/" aria-label="Author page of Ryan Trimble">
<img alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/7dc839d600a4fd344ca6699b2e06ef69" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/7dc839d600a4fd344ca6699b2e06ef69 2x" class="avatar avatar-80 photo" height="80" width="80" loading="lazy" decoding="async" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/ryantrimble/">
Ryan Trimble </a>
</div>
</article>
<article class="in-article-card " id="mini-post-14125">
<time datetime="2011-09-06" title="Originally published Sep 6, 2011">
<strong>
Almanac
</strong>
on
Dec 13, 2024 </time>
<h3>
<a href="https://css-tricks.com/almanac/properties/t/transition/">
transition </a>
</h3>
<a href="https://css-tricks.com/almanac/properties/t/transition/" class="almanac-example">
<code class="language-css">.element { transition: background-color 0.5s ease; }</code>
</a>
<div class="tags">
<a href="https://css-tricks.com/tag/animation/" rel="tag">animation</a> </div>
<div class="author-row">
<a href="https://css-tricks.com/author/saracope/" aria-label="Author page of Sara Cope">
<img alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/84da92f298e5b124d92fb581b82cfdf4" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/84da92f298e5b124d92fb581b82cfdf4 2x" class="avatar avatar-80 photo" height="80" width="80" loading="lazy" decoding="async" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/saracope/">
Sara Cope </a>
</div>
</article>
<article class="in-article-card " id="mini-post-22467">
<time datetime="2013-07-19" title="Originally published Jul 19, 2013">
<strong>
Almanac
</strong>
on
Dec 18, 2024 </time>
<h3>
<a href="https://css-tricks.com/almanac/properties/t/transition-duration/">
transition-duration </a>
</h3>
<a href="https://css-tricks.com/almanac/properties/t/transition-duration/" class="almanac-example">
<code class="language-css">.element { transition-duration: 3s; }</code>
</a>
<div class="tags">
<a href="https://css-tricks.com/tag/animation/" rel="tag">animation</a> </div>
<div class="author-row">
<a href="https://css-tricks.com/author/lazaris/" aria-label="Author page of Louis Lazaris">
<img alt="" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/b8eb0184e62e8a6e71a2d1d7be558248" srcset="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/b8eb0184e62e8a6e71a2d1d7be558248 2x" class="avatar avatar-80 photo" height="80" width="80" loading="lazy" decoding="async" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/lazaris/">
Louis Lazaris </a>
</div>
</article>
<article class="in-article-card " id="mini-post-381314">
<time datetime="2024-10-01" title="Originally published Oct 1, 2024">
<strong>
Almanac
</strong>
on
Dec 13, 2024 </time>
<h3>
<a href="https://css-tricks.com/almanac/rules/s/supports/">
@supports </a>
</h3>
<a href="https://css-tricks.com/almanac/rules/s/supports/" class="almanac-example">
<code class="language-css">@supports selector(:nth-child(1 of .foo)) { }</code>
</a>
<div class="tags">
<a href="https://css-tricks.com/tag/supports/" rel="tag">@supports</a> <a href="https://css-tricks.com/tag/accessibility/" rel="tag">accessibility</a> </div>
<div class="author-row">
<a href="https://css-tricks.com/author/monknow/" aria-label="Author page of Juan Diego Rodríguez">
<img loading="lazy" alt="" class="avatar avatar-80 photo avatar-default" height="80" src="https://css-tricks.com/wp-content/cache/breeze-extra/gravatars/juan-diego-rodriguez-80x80.png" width="80" referrerpolicy="no-referrer"> </a>
<a class="author-name" href="https://css-tricks.com/author/monknow/">
Juan Diego Rodríguez </a>
</div>
</article>
</div>
</description>
<link>https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/</link>
<guid isPermaLink="false">https://css-tricks.com/almanac/rules/m/media/prefers-reduced-motion/</guid>
<pubDate>Fri, 20 Dec 2024 15:35:21 GMT</pubDate>
<author>Geoff Graham</author>
</item>
<item>
<title>@media</title>
<description><p>The CSS <code>@media</code> at-rule lets us target browsers by certain characteristics, features, and user preferences, then apply styles or run other code based on those things.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* When the browser is at least 600px and above */
@media screen and (min-width: 600px) {
.element {
/* Styles! */
}
}</code></pre>
<p class="explanation">This entry summarizes our <a href="https://css-tricks.com/a-complete-guide-to-css-media-queries/">CSS Media Queries Guide</a> by <a href="https://css-tricks.com/author/agalante/">Andrés Galante</a>.</p>
<h3 class="wp-block-heading" id="syntax"><a href="https://css-tricks.com/almanac/rules/m/media/#aa-syntax" aria-hidden="true" class="aal_anchor" id="aa-syntax"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Syntax</h3>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@media [media-type] ([media-feature]) { }</code></pre>
<figure class="wp-block-image size-full"><img loading="lazy" data-recalc-dims="1" fetchpriority="high" decoding="async" width="1000" height="66" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/syntax.png?resize=1000%2C66&amp;ssl=1" alt="Syntax for CSS media queries" class="wp-image-383316" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/syntax.png?w=1000&amp;ssl=1 1000w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/syntax.png?resize=300%2C20&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/syntax.png?resize=768%2C51&amp;ssl=1 768w" sizes="(min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<ul class="wp-block-list">
<li><strong><code>@media</code>:</strong> the starting block of a media query </li>
<li><strong><code>[media-type]</code>:</strong> Users can consume webpages through different kinds of media. This argument defines the type of media we are trying to target</li>
<li><strong><code>[media-feature]</code>:</strong> The type of features we are trying to match the media query to.</li>
<li><strong><code>operator</code>:</strong> &nbsp;Logical operators used to match and combine media types based on certain conditions.</li>
</ul>
<h3 class="wp-block-heading" id="media-types"><a href="https://css-tricks.com/almanac/rules/m/media/#aa-media-types" aria-hidden="true" class="aal_anchor" id="aa-media-types"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Media types</h3>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@media all {}
@media print {}
@media screen {}
@media speech {}</code></pre>
<p>What type of media are we trying to target? In many (if not most) cases, you’ll see a screen value used here, which makes sense since many of the media types we’re trying to match are devices with screens attached to them.</p>
<p>But screens aren’t the only type of media we can target, of course. We have a few, including:</p>
<ul class="wp-block-list">
<li><strong><code>all</code></strong>: Matches all devices</li>
<li><strong><code>print</code></strong>: Matches documents that are viewed in a print preview or any media that breaks the content up into pages intended to print.</li>
<li><strong><code>screen</code></strong>: Matches devices with a screen</li>
<li><strong><code>speech</code></strong>: Matches devices that read the content audibly, such as a screen reader. This replaces the now deprecated aural type since Media Queries Level 4.</li>
</ul>
<h3 class="wp-block-heading" id="media-features"><a href="https://css-tricks.com/almanac/rules/m/media/#aa-media-features" aria-hidden="true" class="aal_anchor" id="aa-media-features"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Media Features</h3>
<p>Once we define the type of media we’re trying to match, we can start defining what features we are trying to match it to. We’ve looked at a lot of examples that match screens to width, but there are many, many (many!) more “features” we can match. <a href="https://www.w3.org/TR/mediaqueries-5/#mf-user-preferences" rel="noopener">Media Queries Level 5</a> groups media features into 6 categories.</p>
<h4 class="wp-block-heading" id="viewport-page-characteristics"><a href="https://css-tricks.com/almanac/rules/m/media/#aa-viewport-page-characteristics" aria-hidden="true" class="aal_anchor" id="aa-viewport-page-characteristics"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Viewport/Page Characteristics</h4>
<p>Here’s the content of the table converted into a bullet list:</p>
<ul class="wp-block-list">
<li><strong><code>width</code></strong>: Defines the width of the viewport. This can be a specific number (e.g., 400px) or a range (using min-width and max-width).</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Value: &lt;length&gt; */
@media screen and (min-width: 600px) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>height</code></strong>: Defines the height of the viewport. This can be a specific number (e.g., 400px) or a range (using min-height and max-height).</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Value: &lt;length&gt; */
@media screen and (max-height: 600px) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>aspect-ratio</code></strong>: Defines the width-to-height aspect ratio of the viewport.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Value: &lt;ratio&gt; */
@media screen and (min-aspect-ratio: 3/4) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>orientation</code></strong>: Refers to the way the screen is oriented, such as tall (portrait) or wide (landscape) based on how the device is rotated.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Value: portrait | landscape */
@media screen and (orientation: landscape) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>overflow-block</code></strong>: Checks how the device treats content that overflows the viewport in the block direction.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Value: none | scroll | paged */
@media (overflow-block: paged) { }</code></pre>
<ul class="wp-block-list">
<li><strong><code>overflow-inline</code></strong>: Checks if content that overflows the viewport along the inline axis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 5 out of 7 changed files in this pull request and generated no comments.
Files not reviewed (2)
- lib/routes/30secondsofcode/utils.ts: Evaluated as low risk
- lib/routes/css-tricks/namespace.ts: Evaluated as low risk
note that css tricks already provides rss feeds: https://css-tricks.com/rss-feeds/ |
yes, but they dont provide for |
Successfully generated as following: http://localhost:1200/css-tricks/articles - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Articles - CSS-Tricks</title>
<link>https://css-tricks.com/category/articles/</link>
<atom:link href="http://localhost:1200/css-tricks/articles" rel="self" type="application/rss+xml"></atom:link>
<description>Latest Articles - CSS-Tricks - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Sat, 18 Jan 2025 06:20:25 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>Fancy Menu Navigation Using Anchor Positioning</title>
<description><p>You have for sure heard about the new <a href="https://css-tricks.com/css-anchor-positioning-guide/">CSS Anchor Positioning</a>, right? It’s a feature that allows you to link any element from the page to another one, i.e., the anchor. It’s useful <a href="https://css-tricks.com/the-little-triangle-in-the-tooltip/">for all the tooltip stuff</a>, but it can also create a lot of other nice effects.</p>
<p>In this article, we will study menu navigation where I rely on anchor positioning to create a nice hover effect on links.</p>
<!--more-->
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_ExzEjoQ" src="https://codepen.io/anon/embed/ExzEjoQ?height=450&amp;theme-id=1&amp;slug-hash=ExzEjoQ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed ExzEjoQ" title="CodePen Embed ExzEjoQ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Cool, right? We have a sliding effect where the blue rectangle adjusts to fit perfectly with the text content over a nice transition. If you are new to anchor positioning, this example is perfect for you because it’s simple and allows you to discover the basics of this new feature. We will also study another example so stay until the end!</p>
<p class="is-style-explanation">Note that only Chromium-based browsers fully support <a href="https://css-tricks.com/css-anchor-positioning-guide/">anchor positioning</a> at the time I’m writing this. You’ll want to view the demos in a browser like Chrome or Edge until the feature is more widely supported in other browsers.</p>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="anchor-positioning"></baseline-status>
<h3 class="wp-block-heading" id="the-initial-configuration">The initial configuration</h3>
<p>Let’s start with the HTML structure which is nothing but a <code>nav</code> element containing an unordered list of links:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;nav&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#"&gt;Home&lt;/a&gt;&lt;/li&gt;
&lt;li class="active"&gt;&lt;a href="#"&gt;About&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#"&gt;Projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#"&gt;Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#"&gt;Contact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/nav&gt;</code></pre>
<p>We will not spend too much time explaining this structure because it can be different if your use case is different. Simply ensure the semantic is relevant to what you are trying to do. As for the CSS part, we will start with some basic styling to create a horizontal menu navigation.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ul {
padding: 0;
margin: 0;
list-style: none;
display: flex;
gap: .5rem;
font-size: 2.2rem;
}
ul li a {
color: #000;
text-decoration: none;
font-weight: 900;
line-height: 1.5;
padding-inline: .2em;
display: block;
}</code></pre>
<p>Nothing fancy so far. We remove some default styling and use Flexbox to align the elements horizontally.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_WbeXzea/76e1215907af780bb1840f1c28c18c52" src="https://codepen.io/anon/embed/preview/WbeXzea/76e1215907af780bb1840f1c28c18c52?height=450&amp;theme-id=1&amp;slug-hash=WbeXzea/76e1215907af780bb1840f1c28c18c52&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed WbeXzea/76e1215907af780bb1840f1c28c18c52" title="CodePen Embed WbeXzea/76e1215907af780bb1840f1c28c18c52" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="sliding-effect">Sliding effect</h3>
<p>First off, let’s understand how the effect works. At first glance, it looks like we have one rectangle that shrinks to a small height, moves to the hovered element, and then grows to full height. That’s the visual effect, but in reality, more than one element is involved!</p>
<p>Here is the first demo where I am using different colors to better see what is happening.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_ZYzaxbz/39b653e638908bf0e207bdcb8b742dc3" src="https://codepen.io/anon/embed/preview/ZYzaxbz/39b653e638908bf0e207bdcb8b742dc3?height=450&amp;theme-id=1&amp;slug-hash=ZYzaxbz/39b653e638908bf0e207bdcb8b742dc3&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed ZYzaxbz/39b653e638908bf0e207bdcb8b742dc3" title="CodePen Embed ZYzaxbz/39b653e638908bf0e207bdcb8b742dc3" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Each menu item has its own “element” that shrinks or grows. Then we have a common “element” (the one in red) that slides between the different menu items. The first effect is done using a background animation and the second one is where anchor positioning comes into play!</p>
<h4 class="wp-block-heading" id="the-background-animation">The background animation</h4>
<p>We will animate the height of a CSS gradient for this first part:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* 1 */
ul li {
background:
conic-gradient(lightblue 0 0)
bottom/100% 0% no-repeat;
transition: .2s;
}
/* 2 */
ul li:is(:hover,.active) {
background-size: 100% 100%;
transition: .2s .2s;
}
/* 3 */
ul:has(li:hover) li.active:not(:hover) {
background-size: 100% 0%;
transition: .2s;
}</code></pre>
<p>We’ve defined a gradient with a <code>100%</code> width and <code>0%</code> height, placed at the bottom. The gradient syntax may look strange, but it’s the shortest one that allows me to have a single-color gradient.</p>
<p class="is-style-explanation"><strong>Related:</strong> <a href="https://css-tip.com/one-color-gradient/" rel="noopener">“How to correctly define a one-color gradient”</a></p>
<p>Then, if the menu item is hovered or has the <code>.active</code> class, we make the height equal to <code>100%</code>. Note the use of the delay here to make sure the growing happens after the shrinking.</p>
<p>Finally, we need to handle a special case with the <code>.active</code> item. If we hover any item (that is <em>not</em> the active one), then the <code>.active</code> item gets the shirking effect (the gradient height is equal to <code>0%</code>). That’s the purpose of the third selector in the code.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_GgKOxxX/ce99779f21c7a6c9991f086ccb6ef1f1" src="https://codepen.io/anon/embed/preview/GgKOxxX/ce99779f21c7a6c9991f086ccb6ef1f1?height=450&amp;theme-id=1&amp;slug-hash=GgKOxxX/ce99779f21c7a6c9991f086ccb6ef1f1&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed GgKOxxX/ce99779f21c7a6c9991f086ccb6ef1f1" title="CodePen Embed GgKOxxX/ce99779f21c7a6c9991f086ccb6ef1f1" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Our first animation is done! Notice how the growing begins <em>after</em> the shrinking completes because of the delay we defined in the second selector.</p>
<h4 class="wp-block-heading" id="the-anchor-positioning-animation">The anchor positioning animation</h4>
<p>The first animation was quite easy because each item had its own background animation, meaning we didn’t have to care about the text content since the background automatically fills the whole space.</p>
<p>We will use one element for the second animation that slides between all the menu items while adapting its width to fit the text of each item. This is where anchor positioning can help us.</p>
<p>Let’s start with the following code:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ul:before {
content:"";
position: absolute;
position-anchor: --li;
background: red;
transition: .2s;
}
ul li:is(:hover, .active) {
anchor-name: --li;
}
ul:has(li:hover) li.active:not(:hover) {
anchor-name: none;
}</code></pre>
<p>To avoid adding an extra element, I will prefer using a pseudo-element on the <code>ul</code>. It should be absolutely-positioned and we will rely on two properties to activate the anchor positioning.</p>
<p>We define the anchor with the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-name/">anchor-name</a></code> property. When a menu item is hovered or has the <code>.active</code> class, it becomes the anchor element. We also have to remove the anchor from the <code>.active</code> item if another item is in a hovered state (hence, the last selector in the code). In other words, only one anchor is defined at a time.</p>
<p>Then we use the <a href="https://css-tricks.com/almanac/properties/p/position-anchor/"><code>position-anchor</code></a> property to link the pseudo-element to the anchor. Notice how both use the same notation <code>--li</code>. It’s similar to how, for example, we define <code>@keyframes</code> with a specific name and later use it inside an <code>animation</code> property. Keep in mind that you have to use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/dashed-ident" rel="noopener">the <code>&lt;dashed-indent&gt;</code> syntax</a>, meaning the name must always start with two dashes (<code>--</code>).</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_pvzdVMp/e10fbc3380bf477e5fcc9e8c640f94aa" src="https://codepen.io/anon/embed/preview/pvzdVMp/e10fbc3380bf477e5fcc9e8c640f94aa?height=450&amp;theme-id=1&amp;slug-hash=pvzdVMp/e10fbc3380bf477e5fcc9e8c640f94aa&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed pvzdVMp/e10fbc3380bf477e5fcc9e8c640f94aa" title="CodePen Embed pvzdVMp/e10fbc3380bf477e5fcc9e8c640f94aa" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>The pseudo-element is correctly placed but nothing is visible because we didn’t define any dimension! Let’s add the following code:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ul:before {
bottom: anchor(bottom);
left: anchor(left);
right: anchor(right);
height: .2em;
}</code></pre>
<p>The <code>height</code> property is trivial but the <code><a href="https://css-tricks.com/almanac/functions/a/anchor/">anchor()</a></code> is a newcomer. Here’s how Juan Diego describes it in the Almanac:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The CSS <code>anchor()</code> function takes an <a href="https://css-tricks.com/almanac/properties/p/position-anchor/">anchor element’s</a> side and resolves to the <code>&lt;length&gt;</code> where it is positioned. It can only be used in inset properties (e.g. <code>top</code>, <code>bottom</code>, <code>bottom</code>, <code>left</code>, <code>right</code>, etc.), normally to place an absolute-positioned element relative to an anchor.</p>
</blockquote>
<p>Let’s check <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/anchor" rel="noopener">the MDN page</a> as well:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The <code>anchor()</code> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS" rel="noopener">CSS</a> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions" rel="noopener">function</a> can be used within an anchor-positioned element’s <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/anchor#properties_that_accept_anchor_function_values" rel="noopener">inset property</a> values, returning a length value relative to the position of the edges of its associated anchor element.</p>
</blockquote>
<p>Usually, we use <code>left: 0</code> to place an absolute element at the left edge of its containing block (i.e., the nearest ancestor having <code>position: relative</code>). The <code>left: anchor(left)</code> will do the same but instead of the containing block, it will consider the associated anchor element.</p>
<p>That’s all — we are done! Hover the menu items in the below demo and see how the pseudo-element slides between them.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_JoPOZNg/83b683c3b8bfcfc845e412a8a46f85c6" src="https://codepen.io/anon/embed/preview/JoPOZNg/83b683c3b8bfcfc845e412a8a46f85c6?height=450&amp;theme-id=1&amp;slug-hash=JoPOZNg/83b683c3b8bfcfc845e412a8a46f85c6&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed JoPOZNg/83b683c3b8bfcfc845e412a8a46f85c6" title="CodePen Embed JoPOZNg/83b683c3b8bfcfc845e412a8a46f85c6" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Each time you hover over a menu item it becomes the new anchor for the pseudo-element (the <code>ul:before</code>). This also means that the <code>anchor(...)</code> values will change creating the sliding effect! Let’s not forget the use of the transition which is important otherwise, we will have an abrupt change.</p>
<p>We can also write the code differently like this:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ul:before {
content:"";
position: absolute;
inset: auto anchor(right, --li) anchor(bottom, --li) anchor(left, --li);
height: .2em;
background: red;
transition: .2s;
}</code></pre>
<p>In other words, we can rely on the <code>inset</code> shorthand instead of using physical properties like <code>left</code>, <code>right</code>, and <code>bottom</code>, and instead of defining <code>position-anchor</code>, we can include the anchor’s name inside the <code>anchor()</code> function. We are repeating the same name three times which is probably not optimal here but in some situations, you may want your element to consider multiple anchors, and in such cases, this syntax will make sense.</p>
<h4 class="wp-block-heading" id="combining-both-effects">Combining both effects</h4>
<p>Now, we combine both effects and, <em>tada</em>, the illusion is perfect!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_ExzEjoQ" src="https://codepen.io/anon/embed/preview/ExzEjoQ?height=450&amp;theme-id=1&amp;slug-hash=ExzEjoQ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed ExzEjoQ" title="CodePen Embed ExzEjoQ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Pay attention to the transition values where the delay is important:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="2,10"><code markup="tt">ul:before {
transition: .2s .2s;
}
ul li {
transition: .2s;
}
ul li:is(:hover,.active) {
transition: .2s .4s;
}
ul:has(li:hover) li.active:not(:hover) {
transition: .2s;
}</code></pre>
<p>We have a sequence of three animations — shrink the height of the gradient, slide the pseudo-element, and grow the height of the gradient — so we need to have delays between them to pull everything together. That’s why for the sliding of the pseudo-element we have a delay equal to the duration of one animation (<code>transition: .2 .2s</code>) and for the growing part the delay is equal to twice the duration (<code>transition: .2s .4s</code>).</p>
<h3 class="wp-block-heading" id="bouncy-effect-why-not-">Bouncy effect? Why not?!</h3>
<p>Let’s try another fancy animation in which the highlight rectangle morphs into a small circle, jumps to the next item, and transforms back into a rectangle again!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_jOozyLY" src="https://codepen.io/anon/embed/preview/jOozyLY?height=450&amp;theme-id=1&amp;slug-hash=jOozyLY&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed jOozyLY" title="CodePen Embed jOozyLY" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>I won’t explain too much for this example as it’s your homework to dissect the code! I’ll offer a few hints so you can unpack what’s happening.</p>
<p>Like the previous effect, we have a combination of two animations. For the first one, I will use the pseudo-element of each menu item where I will adjust the dimension and the <code>border-radius</code> to simulate the morphing. For the second animation, I will use the <code>ul</code> pseudo-element to create a small circle that I move between the menu items.</p>
<p>Here is another version of the demo with different coloration and a slower transition to better visualize each animation:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_dPbZaBO/0eb8245bc557d829240ab836fa4804c3" src="https://codepen.io/anon/embed/preview/dPbZaBO/0eb8245bc557d829240ab836fa4804c3?height=450&amp;theme-id=1&amp;slug-hash=dPbZaBO/0eb8245bc557d829240ab836fa4804c3&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed dPbZaBO/0eb8245bc557d829240ab836fa4804c3" title="CodePen Embed dPbZaBO/0eb8245bc557d829240ab836fa4804c3" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>The tricky part is the jumping effect where I am using a strange <code>cubic-bezier()</code> but I have a detailed article where I explain the technique in my CSS-Tricks article <a href="https://css-tricks.com/advanced-css-animation-using-cubic-bezier/">“Advanced CSS Animation Using <code>cubic-bezier()</code>”</a>.</p>
<h3 class="wp-block-heading" id="conclusion">Conclusion</h3>
<p>I hope you enjoyed this little experimentation using the anchor positioning feature. We only looked at three properties/values but it’s enough to prepare you for this new feature. The <code>anchor-name</code> and <code>position-anchor</code> properties are the mandatory pieces for linking one element (often called a “target” element in this context) to another element (what we call an “anchor” element in this context). From there, you have the <code>anchor()</code> function to control the position.</p>
<p class="is-style-explanation"><strong>Related:</strong> <a href="https://css-tricks.com/css-anchor-positioning-guide/">CSS Anchor Positioning Guide</a></p>
</description>
<link>https://css-tricks.com/fancy-menu-navigation-using-anchor-positioning/</link>
<guid isPermaLink="false">https://css-tricks.com/fancy-menu-navigation-using-anchor-positioning/</guid>
<pubDate>Fri, 17 Jan 2025 06:57:39 GMT</pubDate>
<author>Temani Afif</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2025/01/menu-link-hover-effect.gif" type="image/jpeg"></enclosure>
<category>anchor positioning</category>
<category>Links &amp; URLs</category>
</item>
<item>
<title>Web-Slinger.css: Across the Swiper-Verse</title>
<description><p>My <a href="https://css-tricks.com/web-slinger-css-like-wow-js-but-with-css-y-scroll-animations/">previous article</a> warned that horizontal motion on Tinder has irreversible consequences. I’ll save venting on that topic for a different blog, but at first glance, swipe-based navigation seems like it could be a job for <a href="https://codepen.io/leemeyer/pen/WNVdoNV" rel="noopener">Web-Slinger.css</a>, your friendly neighborhood experimental pure CSS <a href="https://wowjs.uk/" rel="noopener">Wow.js</a> replacement for one-way scroll-triggered animations. I haven’t managed to fit that description into a theme song yet, but I’m working on it.</p>
<p>In the meantime, can Web-Slinger.css swing a pure CSS Tinder-style swiping interaction to indicate liking or disliking an element? More importantly, will this experiment give me an excuse to use an image of <a href="https://simpsons.fandom.com/wiki/Spider-Pig_(song" rel="noopener">Spider Pig</a>, in response to popular demand in the bustling comments section of my previous article? Behold the Spider Pig swiper, which I propose as a replacement for captchas because every human with a pulse loves Spider Pig. With that unbiased statement in mind, swipe left or right below (only Chrome and Edge for now) to reveal a counter showing how many people share your stance on Spider Pig.</p>
<!--more-->
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_MYgobxe" src="https://codepen.io/anon/embed/preview/MYgobxe?height=900&amp;theme-id=1&amp;slug-hash=MYgobxe&amp;default-tab=result" height="900" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed MYgobxe" title="CodePen Embed MYgobxe" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="broaden-your-horizons">Broaden your horizons</h3>
<p>The crackpot who invented Web-Slinger.css seems not to have considered horizontal scrolling, but we can patch that maniac’s monstrous creation like so:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">[class^="scroll-trigger-"] {
view-timeline-axis: x;
}</code></pre>
<p>This overrides the default behavior for marker elements with class names using the Web-Slinger convention of <code>scroll-trigger-n</code>, which activates one-way, scroll-triggered animations. By setting the timeline axis to <code>x</code>, the scroll triggers only run when they are revealed by scrolling horizontally rather than vertically (which is the default). Otherwise, the triggers would run straightaway because although they are out of view due to the container’s width, they will all be above the fold vertically when we implement our swiper.</p>
<p>My steps in laying the foundation for the above demo were to <a href="https://codepen.io/suez/pen/MaeVBy/" rel="noopener">fork this awesome JavaScript demo of Tinder-style swiping by Nikolay Talanov</a>, strip out the JavaScript and all the cards except for one, then import Web-Slinger.css and introduce the horizontal patch explained above. Next, I changed the card’s container to <code>position: fixed</code>, and introduced three <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type" rel="noopener">scroll-snapping</a> boxes side-by-side, each the height and width of the viewport. I set the middle slide to <code>scroll-align: center</code> so that the user starts in the middle of the page and has the option to scroll backwards or forwards.</p>
<p class="is-style-explanation"><strong>Sidenote:</strong> When unconventionally using scroll-driven animations like this, a good mindset is that the scrollable element needn’t be responsible for conventionally scrolling anything visible on the page. This approach is reminiscent of how the first thing you do when using <a href="https://css-tricks.com/the-checkbox-hack/">checkbox hacks</a> is hide the checkbox and make the label look like something else. We leverage the CSS-driven behaviors of a scrollable element, but we don’t need the default UI behavior.</p>
<p>I put a <code>div</code> marked with <code>scroll-trigger-1</code> on the third slide and used it to activate a rejection animation on the card like this:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="demo__card on-scroll-trigger-1 reject"&gt;
&lt;!-- HTML for the card --&gt;
&lt;/div&gt;
&lt;main&gt;
&lt;div class="slide"&gt;
&lt;/div&gt;
&lt;div id="middle" class="slide"&gt;
&lt;/div&gt;
&lt;div class="slide"&gt;
&lt;div class="scroll-trigger-1"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/main&gt;</code></pre>
<p>It worked the way I expected! I knew this would be easy! (Narrator: it isn’t, you’ll see why next.)</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="on-scroll-trigger-2 accept"&gt;
&lt;div class="demo__card on-scroll-trigger-2 reject"&gt;
&lt;!-- HTML for the card --&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;main&gt;
&lt;div class="slide"&gt;
&lt;div class="scroll-trigger-2"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id="middle" class="slide"&gt;
&lt;/div&gt;
&lt;div class="slide"&gt;
&lt;div class="scroll-trigger-1"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/main&gt;</code></pre>
<p>After adding this, Spider Pig is automatically ”liked” when the page loads. That would be appropriate for a card that shows a person like myself who everybody automatically likes — after all, a middle-aged guy who spends his days and nights hacking CSS is quite a catch. By contrast, it is possible Spider Pig isn’t everyone’s cup of tea. So, let’s understand why the swipe right implementation would behave differently than the swipe left implementation when we thought we applied the same principles to both implementations.</p>
<h3 class="wp-block-heading" id="take-a-step-back">Take a step back</h3>
<p>This bug drove home to me what <code>view-timeline</code> does and doesn’t do. The lunatic creator of Web-Slinger.css relied on tech that wasn’t made for animations which run only when the user scrolls <em>backwards</em>.</p>
<p>This <a href="https://scroll-driven-animations.style/tools/view-timeline/ranges/" rel="noopener">visualizer</a> shows that no matter what options you choose for <code><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-range" rel="noopener">animation-range</a></code>, the subject wants to complete its animation after it has crossed the viewport in the scrolling direction — which is exactly what we do <em>not</em> want to happen in this particular case.</p>
<p>Fortunately, our friendly neighborhood <a href="https://www.bram.us/" rel="noopener">Bramus</a> from the Chrome Developer Team <a href="https://www.bram.us/2023/10/23/css-scroll-detection/" rel="noopener">has a cool demo showing how to detect scroll direction in CSS</a>. Using the clever <code>--scroll-direction</code> CSS <a href="https://css-tricks.com/using-property-for-css-custom-properties/">custom property</a> Bramus made, we can ensure Spider Pig animates at the right time rather than on load. The trick is to control the appearance of <code>.scroll-trigger-2</code> using a <a href="https://css-tricks.com/digging-deeper-into-container-style-queries/">style query</a> like this:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="20,21,22,23,24"><code markup="tt">:root {
animation: adjust-slide-index 3s steps(3, end), adjust-pos 1s;
animation-timeline: scroll(root x);
}
@property --slide-index {
syntax: "&lt;number&gt;";
inherits: true;
initial-value: 0;
}
@keyframes adjust-slide-index {
to {
--slide-index: 3;
}
}
.scroll-trigger-2 {
display: none;
}
@container style(--scroll-direction: -1) and style(--slide-index: 0) {
.scroll-trigger-2 {
display: block;
}
}</code></pre>
<p>That style query means that the marker with the <code>.scroll-trigger-2</code> class will not be rendered until we are on the previous slide <strong>and</strong> reach it by scrolling backward. Notice that we also introduced another variable named <code>--slide-index</code>, which is controlled by a three-second scroll-driven animation with three steps. It counts the slide we are on, and it is used because we want the user to swipe decisively to activate the dislike animation. We don’t want just any slight breeze to trigger a dislike.</p>
<h3 class="wp-block-heading" id="when-the-swipe-has-been-concluded-one-more-like-i-m-superhuman-">When the swipe has been concluded, one more like (I’m superhuman)</h3>
<p>As mentioned at the outset, measuring how many CSS-Tricks readers dislike Spider Pig versus how many have a soul is important. To capture this crucial stat, I’m using a <a href="https://www.freecounterstat.com/extensions-browser.php?referer=step_3" rel="noopener">third-party counter image</a> as a background for the card underneath the Spider Pig card. It is third-party, but hopefully, it will always work because the website looks like it has survived since the dawn of the internet. I shouldn’t complain because the price is right. I chose the least 1990s-looking counter and used it like this:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@container style(--scroll-trigger-1: 1) {
.result {
background-image: url('https://counter6.optistats.ovh/private/freecounterstat.php?c=qbgw71kxx1stgsf5shmwrb2aflk5wecz');
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
}
.counter-description::after {
content: 'who like spider pig';
}
.scroll-trigger-2 {
display: none;
}
}
@container style(--scroll-trigger-2: 1) {
.result {
background-image: url('https://counter6.optistats.ovh/private/freecounterstat.php?c=abtwsn99snah6wq42nhnsmbp6pxbrwtj');
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
}
.counter-description::after {
content: 'who dislike spider pig';
}
.scroll-trigger-1 {
display: none;
}
}</code></pre>
<h3 class="wp-block-heading" id="scrolls-of-wisdom-lessons-learned">Scrolls of wisdom: Lessons learned</h3>
<p>This hack turned out more complex than I expected, mostly because of the complexity of using scroll-triggered animations that only run when you meet an element by scrolling backward which goes against assumptions made by the current API. That’s a good thing to know and understand. Still, it’s amazing how much power is hidden in the current spec. We can style things based on extremely specific scrolling behaviors if we believe in ourselves. The current API had to be hacked to unlock that power, but I wish we could do something like:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">[class^="scroll-trigger-"] {
view-timeline-axis: x;
view-timeline-direction: backwards; /* &lt;-- this is speculative. do not use! */
}</code></pre>
<p>With an API like that allowing the swipe-right scroll trigger to behave the way I originally imagined, the Spider Pig swiper would not require hacking.</p>
<p>I dream of wider browser support for scroll-driven animations. But I hope to see the spec evolve to give us more flexibility to encourage designers to build nonlinear storytelling into the experiences they create. If not, once animation timelines land in more browsers, it might be time to make Web-Slinger.css more complete and production-ready, to make the more advanced scrolling use cases accessible to the average CSS user.</p>
</description>
<link>https://css-tricks.com/web-slinger-css-across-the-swiper-verse/</link>
<guid isPermaLink="false">https://css-tricks.com/web-slinger-css-across-the-swiper-verse/</guid>
<pubDate>Wed, 15 Jan 2025 07:03:25 GMT</pubDate>
<author>Lee Meyer</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2025/01/swipe-direction.jpg" type="image/jpeg"></enclosure>
<category>Scroll Driven Animation</category>
</item>
<item>
<title>How to Wait for the sibling-count() and sibling-index() Functions</title>
<description><p>New features don’t just pop up in CSS (but I wish they did). Rather, they go through an extensive process of discussions and considerations, defining, writing, prototyping, testing, shipping handling support, and many more verbs that I can’t even begin to imagine. That process is <strong>long</strong>, and despite how much I want to get my hands on a new feature, as an everyday developer, I can only wait.</p>
<p>I can, however, control how I wait: do I avoid all possible interfaces or demos that are possible with that one feature? Or do I push the boundaries of CSS and try to do them anyway?</p>
<p>As ambitious and curious developers, many of us choose the latter option. CSS would grow stagnant without that mentality. That’s why, today, I want to look at two upcoming functions: <code>sibling-count()</code> and <code>sibling-index()</code>. We’re waiting for them — and have been for several years — so I’m letting my natural curiosity get the best of me so I can get a feel for what to be excited about. Join me!</p>
<!--more-->
<h3 class="wp-block-heading" id="the-tree-counting-functions">The tree-counting functions</h3>
<p>At some point, you’ve probably wanted to know the position of an element amongst its siblings or how many children an element has to calculate something in CSS, maybe for some staggering animation in which each element has a longer delay, or perhaps for changing an element’s <code>background-color</code> depending on its number of siblings. This has been a long-awaited deal on my <a href="https://css-tricks.com/a-css-wishlist-for-2025/">CSS wishlists</a>. Take this <a href="https://github.com/w3c/csswg-drafts/issues/1026" rel="noopener">CSSWG GitHub Issue</a> from 2017:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Feature request. It would be nice to be able to use the <code>counter()</code> function inside of <code>calc()</code> function. That would enable new possibilities on layouts.</p>
</blockquote>
<p>However, counters work using strings, rendering them useless inside a <code>calc()</code> function that deals with numbers. We need a set of similar functions that return <strong>as integers</strong> the index of an element and the count of siblings. This doesn’t seem too much to ask. We can currently query an element by its tree position using the <code><a href="https://css-tricks.com/almanac/pseudo-selectors/n/nth-child/">:nth-child()</a></code> pseudo-selector (and its variants), not to mention query an element based on how many items it has using the <code><a href="https://css-tricks.com/almanac/pseudo-selectors/h/has/">:has()</a></code> pseudo-selector.</p>
<p>Luckily, this year the <a href="https://github.com/w3c/csswg-drafts/issues/4559" rel="noopener">CSSWG approved implementing the <code>sibling-count()</code> and <code>sibling-index()</code> functions</a>! And we already have something in the spec written down:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The <code>sibling-count()</code> functional notation represents, as an <code>&lt;integer&gt;</code>, the total number of child elements in the parent of the element on which the notation is used.</p>
<p>The <code>sibling-index()</code> functional notation represents, as an <code>&lt;integer&gt;</code>, the index of the element on which the notation is used among the children of its parent. Like <code>:nth-child()</code>, <code>sibling-index()</code> is 1-indexed.</p>
</blockquote>
<p>How much time do we have to wait to use them? Earlier this year <a href="https://x.com/argyleink/status/1800565839214858335">Adam Argyle said</a> that “a Chromium engineer mentioned wanting to do it, but we don’t have a flag to try it out with yet. I’ll share when we do!” So, while I am hopeful to get more news in 2025, we probably won’t see them shipped soon. In the meantime, let’s get to what we can do right now!</p>
<h3 class="wp-block-heading" id="rubbing-two-sticks-together">Rubbing two sticks together</h3>
<p>The closest we can get to tree counting functions in terms of syntax and usage is with custom properties. However, the biggest problem is populating them with the correct index and count. The simplest and longest method is hardcoding each using only CSS: we can use the <code>nth-child()</code> selector to give each element its corresponding index:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(1) {
--sibling-index: 1;
}
li:nth-child(2) {
--sibling-index: 2;
}
li:nth-child(3) {
--sibling-index: 3;
}
/* and so on... */</code></pre>
<p>Setting the <code>sibling-count()</code> equivalent has a bit more nuance since we will need to use quantity queries with the <code>:has()</code> selector. A quantity query has the following syntax:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.container:has(&gt; :last-child:nth-child(m)) { }</code></pre>
<p>…where <code>m</code> is the number of elements we want to target. It works by checking if the last element of a container is also the <code>nth</code> element we are targeting; thus it has only that number of elements. You can create your custom <a href="https://css-tip.com/quantity-queries/" rel="noopener">quantity queries using this tool by Temani Afif</a>. In this case, our quantity queries would look like the following:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ol:has(&gt; :nth-child(1)) {
--sibling-count: 1;
}
ol:has(&gt; :last-child:nth-child(2)) {
--sibling-count: 2;
}
ol:has(&gt; :last-child:nth-child(3)) {
--sibling-count: 3;
}
/* and so on... */</code></pre>
<p>This example is intentionally light on the number of elements for brevity, but as the list grows it will become unmanageable. Maybe we could use a preprocessor like Sass to write them for us, but we want to focus on a vanilla CSS solution here. For example, the following demo can support up to 12 elements, and you can already see how ugly it gets in the code.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_gbYWzgR" src="https://codepen.io/anon/embed/gbYWzgR?height=450&amp;theme-id=1&amp;slug-hash=gbYWzgR&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed gbYWzgR" title="CodePen Embed gbYWzgR" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>That’s 24 rules to know the index and count of 12 elements for those of you keeping score. It surely feels like we could get that number down to something more manageable, but if we hardcode each index we are bound increase the amount of code we write. The best we can do is rewrite our CSS so we can nest the <code>--sibling-index</code> and <code>--sibling-count</code> properties together. Instead of writing each property by itself:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(2) {
--sibling-index: 2;
}
ol:has(&gt; :last-child:nth-child(2)) {
--sibling-count: 2;
}</code></pre>
<p>We could instead nest the <code>--sibling-count</code> rule inside the <code>--sibling-index</code> rule.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(2) {
--sibling-index: 2;
ol:has(&gt; &amp;:last-child) {
--sibling-count: 2;
}
}</code></pre>
<p>While it may seem wacky to nest a parent inside its children, the following CSS code is completely valid; we are selecting the second <code>li</code> element, and inside, we are selecting an <code>ol</code> element if its second <code>li</code> element is also the last, so the list only has two elements. Which syntax is easier to manage? It’s up to you.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_RNbZYgP" src="https://codepen.io/anon/embed/RNbZYgP?height=450&amp;theme-id=1&amp;slug-hash=RNbZYgP&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed RNbZYgP" title="CodePen Embed RNbZYgP" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>But that’s just a slight improvement. If we had, say, 100 elements we would still need to hardcode the <code>--sibling-index</code> and <code>--sibling-count</code> properties 100 times. Luckily, the following method will increase rules in a logarithmic way, specifically base-2. So instead of writing 100 rules for 100 elements, we will be writing closer to 10 rules for around 100 elements.</p>
<h3 class="wp-block-heading" id="flint-and-steel">Flint and steel</h3>
<p>This method was first described by <a href="https://kizu.dev/tree-counting-and-random/#prototyping-with-custom-properties" rel="noopener">Roman Komarov in October last year</a>, in which he prototypes both tree counting functions and the future <code><a href="https://css-tricks.com/almanac/functions/r/random/">random()</a></code> function. It’s an amazing post, so I strongly encourage you to read it.</p>
<p>This method also uses custom properties, but instead of hardcoding each one, we will be using two custom properties that will build up the <code>--sibling-index</code> property for each element. Just to be consistent with Roman’s post, we will call them <code>--si1</code> and <code>--si2</code>, both starting at <code>0</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li {
--si1: 0;
--si2: 0;
}</code></pre>
<p>The real <code>--sibling-index</code> will be constructed using both properties and a <strong>factor</strong> (<code>F</code>) that represents an integer greater or equal to <code>2</code> that tells us how many elements we can select according to the formula <code>sqrt(F) - 1</code>. So…</p>
<ul class="wp-block-list">
<li>For a factor of <code>2</code>, we can select <code>3</code> elements.</li>
<li>For a factor of <code>3</code>, we can select <code>8</code> elements.</li>
<li>For a factor of <code>5</code>, we can select <code>24</code> elements.</li>
<li>For a factor of <code>10</code>, we can select <code>99</code> elements.</li>
<li>For a factor of <code>25</code>, we can select <code>624</code> elements.</li>
</ul>
<p>As you can see, increasing the factor by one will give us exponential gains on how many elements we can select. But how does all this translate to CSS?</p>
<p>The first thing to know is that the formula for calculating the <code>--sibling-index</code> property is <code>calc(F * var(--si2) + var(--si1))</code>. If we take a factor of <code>3</code>, it would look like the following:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li {
--si1: 0;
--si2: 0;
/* factor of 3; it's a harcoded number */
--sibling-index: calc(3 * var(--si2) + var(--si1));
}</code></pre>
<p>The following selectors may be random but stay with me here. For the <code>--si1</code> property, we will write rules selecting elements that are multiples of the factor and offset them by one <code>1</code> until we reach <code>F - 1</code>, then set <code>--si1</code> to the offset. This translates to the following CSS:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(Fn + 1) { --si1: 1; }
li:nth-child(Fn + 2) { --si1: 2; }
/* ... */
li:nth-child(Fn+(F-1)) { --si1: (F-1) }</code></pre>
<p>So if our factor is <code>3</code>, we will write the following rules until we reach <code>F-1</code>, so <code>2</code> rules:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(3n + 1) { --si1: 1; }
li:nth-child(3n + 2) { --si1: 2; }</code></pre>
<p>For the <code>--si2</code> property, we will write rules selecting elements in batches of the factor (so if our factor is <code>3</code>, we will select <code>3</code> elements per rule), going from the last possible index (in this case <code>8</code>) backward until we simply are unable to select more elements in batches. This is a little more convoluted to write in CSS:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(n + F*1):nth-child(-n + F*1-1){--si2: 1;}
li:nth-child(n + F*2):nth-child(-n + F*2-1){--si2: 2;}
/* ... */
li:nth-child(n+(F*(F-1))):nth-child(-n+(F*F-1)) { --si2: (F-1) }</code></pre>
<p>Again, if our factor is <code>3</code>, we will write the following two rules:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(n + 3):nth-child(-n + 5) {
--si2: 1;
}
li:nth-child(n + 6):nth-child(-n + 8) {
--si2: 2;
}</code></pre>
<p>And that’s it! By only setting those two values for <code>--si1</code> and <code>--si2</code> we can count up to <code>8</code> total elements. The math behind how it works seems wacky at first, but once you visually get it, it all clicks. I made this interactive demo in which you can see how all elements can be reached using this formula. Hover over the code snippets to see which elements can be selected, and click on each snippet to combine them into a possible index.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_QwLMVom" src="https://codepen.io/anon/embed/QwLMVom?height=600&amp;theme-id=1&amp;slug-hash=QwLMVom&amp;default-tab=result" height="600" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed QwLMVom" title="CodePen Embed QwLMVom" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>If you crank the elements and factor to the max, you can see that we can select 48 elements using only 14 snippets!</p>
<p><strong>Wait, one thing is missing: the <code>sibling-count()</code> function.</strong> Luckily, we will be reusing all we have learned from prototyping <code>--sibling-index</code>. We will start with two custom properties: <code>--sc1</code> and <code>--sc1</code> at the container, both starting at <code>0</code> as well. The formula for calculating <code>--sibling-count</code> is the same.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ol {
--sc1: 0;
--sc2: 0;
/* factor of 3; also a harcoded number */
--sibling-count: calc(3 * var(--sc2) + var(--sc1));
}</code></pre>
<p>Roman’s post also explains how to write selectors for the <code>--sibling-count</code> property by themselves, but we will use the <code>:has()</code> selection method from our first technique so we don’t have to write extra selectors. We can cram those <code>--sc1</code> and <code>--sc2</code> properties into the rules where we defined the <code>sibling-index()</code> properties:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* --si1 and --sc1 */
li:nth-child(3n + 1) {
--si1: 1;
ol:has(&gt; &amp;:last-child) {
--sc1: 1;
}
}
li:nth-child(3n + 2) {
--si1: 2;
ol:has(&gt; &amp;:last-child) {
--sc1: 2;
}
}
/* --si2 and --sc2 */
li:nth-child(n + 3):nth-child(-n + 5) {
--si2: 1;
ol:has(&gt; &amp;:last-child) {
--sc2: 1;
}
}
li:nth-child(n + 6):nth-child(-n + 8) {
--si2: 2;
ol:has(&gt; &amp;:last-child) {
--sc2: 2;
}
}</code></pre>
<p>This is using a factor of <code>3</code>, so we can count up to eight elements with only four rules. The following example has a factor of <code>7</code>, so we can count up to 48 elements with only 14 rules.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_bNbgOMZ" src="https://codepen.io/anon/embed/bNbgOMZ?height=600&amp;theme-id=1&amp;slug-hash=bNbgOMZ&amp;default-tab=css,result" height="600" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed bNbgOMZ" title="CodePen Embed bNbgOMZ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>This method is great, but may not be the best fit for everyone due to the almost magical way of how it works, or simply because you don’t find it aesthetically pleasing. While for avid hands lighting a fire with flint and steel is a breeze, many won’t get their fire started.</p>
<h3 class="wp-block-heading" id="using-a-flamethrower">Using a flamethrower</h3>
<p>For this method, we will use once again custom properties to mimic the tree counting functions, and what’s best, we will write less than 20 lines of code to count up to infinity—or I guess to <code>1.7976931348623157e+308</code>, which is the double precision floating point limit!</p>
<p>We will be using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" rel="noopener">Mutation Observer API</a>, so of course it takes JavaScript. I know that’s like admitting defeat for many, but I disagree. If the JavaScript method is simpler (which it is, by far, in this case), then it’s the most appropriate choice. Just as a side note, if performance is your main worry, stick to hard-coding each index in CSS or HTML.</p>
<p>First, we will grab our container from the DOM:</p>
<pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">const elements = document.querySelector("ol");</code></pre>
<p>Then we’ll create a function that sets the <code>--sibling-index</code> property in each element and the <code>--sibling-count</code> in the container (it will be available to its children due to the cascade). For the <code>--sibling-index</code>, we have to loop through the <code>elements.children</code>, and we can get the <code>--sibling-count</code> from <code>elements.children.length</code>.</p>
<pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">const updateCustomProperties = () =&gt; {
let index = 1;
for (element of elements.children) {
element.style.setProperty("--sibling-index", index);
index++;
}
elements.style.setProperty("--sibling-count", elements.children.length);
};</code></pre>
<p>Once we have our function, remember to call it once so we have our initial tree counting properties:</p>
<pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">updateCustomProperties();</code></pre>
<p>Lastly, the Mutation Observer. We need to initiate a new observer using the <code>MutationObserver</code> constructor. It takes a callback that gets invoked each time the elements change, so we write our <code>updateCustomProperties</code> function. With the resulting <code>observer</code> object, we can call its <code>observe()</code> method which takes two parameters:</p>
<ol class="wp-block-list">
<li>the element we want to observe, and</li>
<li>a <code>config</code> object ... |
http://localhost:1200/css-tricks/guides - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Latest CSS Guides</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/guides" rel="self" type="application/rss+xml"></atom:link>
<description>Dive deep into CSS features and concepts - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Sat, 18 Jan 2025 06:20:29 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>CSS Anchor Positioning Guide</title>
<description><div class="wp-block-columns are-vertically-aligned-top is-layout-flex wp-container-core-columns-is-layout-1 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66%">
<p>Not long ago, if we wanted a tooltip or popover positioned on top of another element, we would have to set our tooltip’s position to something other than <code>static</code> and use its inset/transform properties to place it <em>exactly</em> where we want. This works, but the element’s position is susceptible to user scrolls, zooming, or animations since the tooltip could overflow off of the screen or wind up in an awkward position. The only way to solve this was using JavaScript to check whenever the tooltip goes out of bounds so we can correct it… again in JavaScript.</p>
<p> CSS Anchor Positioning gives us a simple interface to attach elements next to others just by saying which sides to connect — directly in CSS. It also lets us set a fallback position so that we can avoid the overflow issues we just described. For example, we might set a tooltip element above its anchor but allow it to fold underneath the anchor when it runs out of room to show it above.</p>
<p>Anchor positioning is different from a lot of other features as far as how quickly it’s gained browser support: its <a href="https://www.w3.org/standards/history/css-anchor-position-1/" rel="noopener">first draft was published on June 2023</a> and, just a year later, it was <a href="https://caniuse.com/css-anchor-positioning" rel="noopener">released on Chrome 125</a>. To put it into perspective, the first draft specification for CSS variables <a href="https://www.w3.org/standards/history/css-variables-1/" rel="noopener">was published in 2012</a>, but it took four years for them to gain wide browser support.</p>
<p>So, let’s dig in and learn about things like attaching target elements to anchor elements and positioning and sizing them.</p>
</div>
<div class="wp-block-column is-vertically-aligned-top ticss-986972e6 is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33%"><h2 class="wp-block-heading" id="quick-reference">Quick reference</h2>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Define an anchor element */
.anchor {
anchor-name: --my-anchor;
}</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Anchor a target element */
.target {
position: absolute;
position-anchor: --my-anchor;
}</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">/* Position a target element */
.target {
position-area: start end;
}</code></pre>
<div class="wp-block-group sticky-toc"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<details>
<summary>
Table of contents </summary>
<ol class="wp-block-list">
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-basics-and-terminology">Basics and terminology</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-attaching-targets-to-anchors">Attaching targets to anchors</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-positioning-targets">Positioning targets</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-setting-fallback-positions">Setting fallback positions</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-custom-position-and-size-fallbacks">Custom position and size fallbacks</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-multiple-anchors">Multiple anchors</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-accessibility">Accessibility</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-browser-support">Browser support</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-spec-changes">Spec changes</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-known-bugs">Known bugs</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-almanac-references">Almanac references</a></li>
<li><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-further-reading">Further reading</a></li>
</ol>
</details></div></div>
</div>
</div>
<div style="height:var(--wp--preset--spacing--60)" aria-hidden="true" class="wp-block-spacer"></div>
<details open="">
<summary>
<h2>Basics and terminology</h2>
</summary>
<p>At its most basic, CSS Anchor Positioning introduces a completely new way of placing elements on the page relative to one another. To make our lives easier, we’re going to use specific names to clarify which element is connecting to which:</p>
<ul class="wp-block-list">
<li><strong>Anchor:</strong> This is the element used as a reference for positioning other elements, hence the <em>anchor</em><strong> </strong>name.</li>
<li><strong>Target:</strong> This is an absolutely positioned element placed relative to one or more anchors. The <em>target</em> is the name we will use from now on, but you will often find it as just an “absolutely positioned element” in the spec.</li>
</ul>
<p>For the following code examples and demos, you can think of these as just two <code>&lt;div&gt;</code> elements next to one another.</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="anchor"&gt;anchor&lt;/div&gt;
&lt;div class="target"&gt;target&lt;/div&gt;</code></pre>
<p>CSS Anchor Positioning is all about elements with absolute positioning (i.e., <code>position: absolute</code>), so there are also some concepts we have to review before diving in.</p>
<ul class="wp-block-list">
<li><strong>Containing Block:</strong> This is the box that contains the elements. For an absolute element, the containing block is the viewport the closest ancestor with a position other than <code>static</code> or certain values in properties like <a href="https://css-tricks.com/almanac/properties/c/contain/"><code>contain</code></a> or <a href="https://css-tricks.com/almanac/properties/f/filter/"><code>filter</code></a>.</li>
<li><strong>Inset-Modified Containing Block (IMCB):</strong> For an absolute element, inset properties (<code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>, etc.) reduce the size of the containing block into which it is sized and positioned, resulting in a new box called the <em>inset-modified containing block</em>, or IMCB for short. This is a vital concept to know since properties we’re covering in this guide — like <code>position-area</code> and <code>position-try-order</code> — rely on this concept.</li>
</ul>
</details>
<details>
<summary>
<h2>Attaching targets to anchors</h2>
</summary>
<p style="font-size:22px">We’ll first look at the two properties that establish anchor positioning. The first, <code>anchor-name</code>, establishes the anchor element, while the second, <code>position-anchor</code>, attaches a target element to the anchor element.</p>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-2 wp-block-columns-is-layout-flex">
<div class="wp-block-column ticss-30288ed1 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1024%2C576&amp;ssl=1" alt="Square labeled as &quot;anchor&quot;" class="wp-image-381095" style="width:300px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-name-7.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="anchorname"><code>anchor-name</code></h4>
<p>A normal element isn’t an anchor by default — we have to explicitly make an element an anchor. The most common way is by giving it a name, which we can do with the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-name/">anchor-name</a></code> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">anchor-name: none | &lt;dashed-ident&gt;#</code></pre>
<p>The name must be a <code>&lt;dashed-ident&gt;</code>, that is, a custom name prefixed with two dashes (<code>--</code>), like <code>--my-anchor</code> or <code>--MyAnchor</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.anchor {
anchor-name: --my-anchor;
}</code></pre>
<p>This gives us an anchor element. All it needs is something anchored to it. That’s what we call the “target” element which is set with the <code>position-anchor</code> property.</p>
</div></div>
</div>
<div class="wp-block-column ticss-bd46f479 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1024%2C576&amp;ssl=1" alt="Square labeled as &quot;target&quot;" class="wp-image-381096" style="width:300px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-anchor-5.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-anchor-"><code>position-anchor</code></h4>
<p>The target element is an element with an absolute position linked to an anchor element matching what’s declared on the <code>anchor-name</code> property. This attaches the target element to the anchor element.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-anchor: auto | &lt;anchor-element&gt;</code></pre>
<p>It takes a valid <code>&lt;anchor-element&gt;</code>. So, if we establish another element as the “anchor” we can set the target with the <code><a href="https://css-tricks.com/almanac/properties/p/position-anchor/">position-anchor</a></code> property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-anchor: --my-anchor;
}</code></pre>
<p>Normally, if a valid anchor element isn’t found, then other anchor properties and functions will be ignored.</p>
</div></div>
</div>
</div>
</div></div>
</details>
<details>
<summary>
<h2>Positioning targets</h2>
</summary>
<p style="font-size:22px">Now that we know how to establish an anchor-target relationship, we can work on <strong>positioning</strong> the target element in relation to the anchor element. The following two properties are used to set which side of the anchor element the target is positioned on (<code>position-area</code>) and conditions for hiding the target element when it runs out of room (<code>position-visibility</code>).</p>
<div class="wp-block-columns are-vertically-aligned-top is-layout-flex wp-container-core-columns-is-layout-3 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top ticss-168d39a5 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1024%2C576&amp;ssl=1" alt="Anchor element with target elements spanning around it." class="wp-image-380907" style="width:640px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-area-9.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-area-"><code>position-area</code></h4>
<p>The next step is positioning our target relative to its anchor. The easiest way is to use the <code>position-area</code> property, which creates an imaginary 3×3 grid around the anchor element and lets us place the target in one or more regions of the grid.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-area: auto | &lt;position-area&gt;</code></pre>
<p>It works by setting the row and column of the grid using&nbsp;<strong>logical values</strong>&nbsp;like&nbsp;<code>start</code>&nbsp;and&nbsp;<code>end</code>&nbsp;(dependent on the writing mode);&nbsp;<strong>physical values</strong>&nbsp;like&nbsp;<code>top</code>,&nbsp;<code>left</code>,&nbsp;<code>right</code>,&nbsp;<code>bottom</code>&nbsp;and the&nbsp;<code>center</code>&nbsp;<strong>shared value</strong>, then it will shrink the target’s IMCB into the region of the grid we chose.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: top right;
/* or */
position-area: start end;
}</code></pre>
<p>Logical values refer to the containing block’s writing mode, but if we want to position our target relative to its writing mode we would prefix it with the <code>self</code> value.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: self-start self-end;
}</code></pre>
<p>There is also the <code>center</code> value that can be used in every axis.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: center right;
/* or */
position-area: start center;
}</code></pre>
<p>To place a target across two adjacent grid regions, we can use the prefix <code>span-</code> on any value (that isn’t <code>center</code>) a row or column at a time.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: span-top left;
/* or */
position-area: span-start start;
}</code></pre>
<p>Finally, we can span a target across three adjacent grid regions using the <code>span-all</code> value.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: bottom span-all;
/* or */
position-area: end span-all;
}</code></pre>
<p>You may have noticed that the <code>position-area</code> property doesn’t have a strict order for physical values; writing<code> position-area: top left</code> is the same as <code>position-area: left top</code>, but the order is important for logical value since <code>position-area: start end</code> is completely opposite to <code>position-area: end start</code>.</p>
<p>We can make logical values interchangeable by prefixing them with the desired axis using <code>y-</code>, <code>x-</code>, <code>inline-</code> or <code>block-</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-area: inline-end block-start;
/* or */
position-area: y-start x-end;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_PormJMG" src="https://codepen.io/anon/embed/preview/PormJMG?height=450&amp;theme-id=1&amp;slug-hash=PormJMG&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed PormJMG" title="CodePen Embed PormJMG" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div></div>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_VwJMxNp" src="https://codepen.io/anon/embed/preview/VwJMxNp?height=450&amp;theme-id=1&amp;slug-hash=VwJMxNp&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed VwJMxNp" title="CodePen Embed VwJMxNp" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div>
<div class="wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group ticss-e32e6402"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1024%2C576&amp;ssl=1" alt="Examples on each position-visibility value: always showing the target, anchors-visible hiding it when the anchor goes out of screen and no-overflow hiding it when the target overflows" class="wp-image-380921" style="width:650px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-visibility-3.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-visibility-"><code>position-visibility</code></h4>
<p>It provides certain conditions to hide the target from the viewport.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-visibility: always | anchors-visible | no-overflow</code></pre>
<ul class="wp-block-list">
<li><strong><code>always</code>:</strong> The target is always displayed without regard for its anchors or its overflowing status.</li>
<li><strong><code>no-overflow</code>:</strong> If even after applying the position fallbacks, the target element is still overflowing its containing block, then it is strongly hidden.</li>
<li><strong><code>anchors-visible</code>:</strong> If the <strong>anchor</strong> (not the target) has completely overflowed its containing block or is completely covered by other elements, then the target is strongly hidden.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-visibility: always | anchors-visible | no-overflow</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_XWLzGVe" src="https://codepen.io/anon/embed/preview/XWLzGVe?height=450&amp;theme-id=1&amp;slug-hash=XWLzGVe&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed XWLzGVe" title="CodePen Embed XWLzGVe" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
</div></div>
</div>
</div>
</details>
<details>
<summary>
<h2>Setting fallback positions</h2>
</summary>
<p style="font-size:22px">Once the target element is positioned against its anchor, we can give the target additional instructions that tell it what to do if it runs out of space. We’ve already looked at the <code>position-visibility</code> property as one way of doing that — we simply tell the element to hide. The following two properties, however, give us more control to <strong>re-position</strong> the target by trying other sides of the anchor (<code>position-try-fallbacks</code>) and the order in which it attempts to re-position itself (<code>position-try-order</code>).</p>
<p>The two properties can be declared together with the <code>position-try</code> shorthand property — we’ll touch on that after we look at the two constituent properties.</p>
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-4 wp-block-columns-is-layout-flex">
<div class="wp-block-column ticss-b9b485c1 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1024%2C576&amp;ssl=1" alt="Examples on each try-tactic: flip-block flipping the target from the top to the bottom, flip-inline from left to right and flip-start from left to top (single value) and top right to left bottom (two values)" class="wp-image-380903" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-fallbacks.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-try-fallbacks-"><code>position-try-fallbacks</code></h4>
<p>This property accepts a list of comma-separated <em>position fallbacks</em> that are tried whenever the target overflows out of space in its containing block. The property attempts to reposition itself using each fallback value until it finds a fit or runs out of options.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try-fallbacks: none | [ [&lt;dashed-ident&gt; || &lt;try-tactic&gt;] | &lt;'inset-area'&gt; ]#</code></pre>
<ul class="wp-block-list">
<li><strong><code>none</code>:</strong> Leaves the target’s position options list empty.</li>
<li><strong><code>&lt;dashed-ident&gt;</code>:</strong> Adds to the options list a custom <code><a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-anchor-at-rule">@position-try</a></code> fallback with the given name. If there isn’t a matching <code>@position-try</code>, the value is ignored.</li>
<li><strong><code>&lt;try-tactic&gt;</code>:</strong> Creates an option list by flipping the target’s current position on one of three axes, each defined by a distinct keyword. They can also be combined to add up their effects.
<ul class="wp-block-list">
<li>The <code>flip-block</code> keyword swaps the values in the block axis.</li>
<li>The <code>flip-inline</code> keyword swaps the values in the inline axis.</li>
<li>The <code>flip-start</code> keyword swaps the values diagonally.</li>
</ul>
</li>
<li><strong><code>&lt;dashed-ident&gt;</code> || <code>&lt;try-tactic&gt;:</code></strong> Combines a custom <code>@try-option</code> and a <code>&lt;try-tactic&gt;</code> to create a single-position fallback. The <code>&lt;try-tactic&gt;</code> keywords can also be combined to sum up their effects.</li>
<li><strong><code>&lt;"position-area"&gt;</code></strong> Uses the <code>position-area</code> syntax to move the anchor to a new position.</li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try-fallbacks:
--my-custom-position,
--my-custom-position flip-inline,
bottom left;
}</code></pre>
</div></div>
</div>
<div class="wp-block-column ticss-69217be6 is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1024%2C576&amp;ssl=1" alt="two targets sorrounding an anchor, positioned where the IMCB is the largest. " class="wp-image-380914" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/position-try-order.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<h4 class="wp-block-heading" id="-position-try-order-"><code>position-try-order</code></h4>
<p>This property chooses a new position from the fallback values defined in the <code>position-try-fallbacks</code> property based on which position gives the target the most space. The rest of the options are reordered with the largest available space coming first.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try-order: normal | most-width | most-height | most-block-size | most-inline-size</code></pre>
<p>What exactly does “more space” mean? For each position fallback, it finds the IMCB size for the target. Then it chooses the value that gives the IMCB the widest or tallest size, depending on which option is selected:</p>
<ul class="wp-block-list">
<li><code>most-width</code></li>
<li><code>most-height</code></li>
<li><code>most-block-size</code></li>
<li><code>most-inline-size</code></li>
</ul>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try-fallbacks: --custom-position, flip-start;
position-try-order: most-width;
}</code></pre>
</div></div>
<h4 class="wp-block-heading" id="-position-try-"><code>position-try</code></h4>
<p>This is a shorthand property that combines the <code>position-try-fallbacks</code> and <code>position-try-order</code> properties into a single declaration. It accepts first the order and then the list of possible position fallbacks.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">position-try: &lt; "position-try-order" &gt;? &lt; "position-try-fallbacks" &gt;;</code></pre>
<p>So, we can combine both properties into a single style rule:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position-try: most-width --my-custom-position, flip-inline, bottom left;
}</code></pre>
</div>
</div>
</details>
<details>
<summary>
<h2>Custom position and size fallbacks</h2>
</summary>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained"><h4 class="wp-block-heading" id="-position-try-"><code>@position-try</code></h4>
<p>This at-rule defines a custom position fallback for the <code>position-try-fallbacks</code> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@position-try &lt;dashed-ident&gt; {
&lt;declaration-list&gt;
}</code></pre>
<p>It takes various properties for changing a target element’s position and size and grouping them as a new position fallback for the element to try.</p>
<p>Imagine a scenario where you’ve established an anchor-target relationship. You want to position the target element against the anchor’s top-right edge, which is easy enough using the <code>position-area</code> property we saw earlier:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-area: top right;
width: 100px;
}</code></pre>
<p>See how the <code>.target</code> is sized at <code>100px</code>? Maybe it runs out of room on some screens and is no longer able to be displayed at anchor’s the top-right edge. We can supply the <code>.target</code> with the fallbacks we looked at earlier so that it attempts to re-position itself on an edge with more space:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="4,5"><code markup="tt">.target {
position: absolute;
position-area: top right;
position-try-fallbacks: top left;
position-try-order: most-width;
width: 100px;
}</code></pre>
<p>And since we’re being good CSSer’s who strive for clean code, we may as well combine those two properties with the <code>position-try</code> shorthand property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="4"><code markup="tt">.target {
position: absolute;
position-area: top right;
position-try: most-width, flip-inline, bottom left;
width: 100px;
}</code></pre>
<p>So far, so good. We have an anchored target element that starts at the top-right corner of the anchor at <code>100px</code>. If it runs out of space there, it will look at the <code>position-try</code> property and decide whether to reposition the target to the anchor’s top-left corner (declared as <code>flip-inline</code>) or the anchor’s bottom-left corner — whichever offers the most width.</p>
<p>But what if we want to simulataneously <strong>re-size</strong> the target element when it is re-positioned? Maybe the target is simply too dang big to display at <code>100px</code> at either fallback position and we need it to be <code>50px</code> instead. We can use the <code>@position-try</code> to do exactly that:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@position-try --my-custom-position {
position-area: top left;
width: 50px;
}</code></pre>
<p>With that done, we now have a custom property called <code>--my-custom-position</code> that we can use on the <code>position-try</code> shorthand property. In this case, <code>@position-try</code> can replace the <code>flip-inline</code> value since it is the equivalent of <code>top left</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line="9"><code markup="tt">@position-try --my-custom-position {
position-area: top left;
width: 50px;
}
.target {
position: absolute;
position-area: top right;
position-try: most-width, --my-custom-position, bottom left;
width: 100px;
}</code></pre>
<p>This way, the <code>.target</code> element’s width is re-sized from <code>100px</code> to <code>50px</code> when it attempts to re-position itself to the anchor’s top-right edge. That’s a nice bit of flexibility that gives us a better chance to make things fit together in any layout.</p>
</div></div>
</div></div>
</details>
<details>
<summary>
<h2>Anchor functions</h2>
</summary>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-5 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group ticss-9c54673b"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained"><h4 class="wp-block-heading" id="-anchor-"><code>anchor()</code></h4>
<p>You might think of the CSS <code>anchor()</code> function as a shortcut for attaching a target element to an anchor element — specify the anchor, the side we want to attach to, and how large we want the target to be in one fell swoop. But, as we’ll see, the function also opens up the possibility of attaching one target element to multiple anchor elements.</p>
<p>This is the function’s formal syntax, which takes up to three arguments:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">anchor( &lt;anchor-element&gt;? &amp;&amp; &lt;anchor-side&gt;, &lt;length-percentage&gt;? )</code></pre>
<p>So, we’re identifying an anchor element, saying which side we want the target to be positioned on, and how big we want it to be. It’s worth noting that <code>anchor()</code> can only be declared on inset-related properties (e.g. <code>top</code>, <code>left</code>, <code>inset-block-end</code>, etc.)</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
top: anchor(--my-anchor bottom);
left: anchor(--my-anchor end, 50%);
}</code></pre>
<p>Let’s break down the function’s arguments.</p>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;anchor-element&gt;</summary>
<p>This argument specifies which anchor element we want to attach the target to. We can supply it with either the anchor’s name (see <a href="https://css-tricks.com/css-anchor-positioning-guide/#aa-attaching-targets-to-anchors">“Attaching targets to anchors”</a>).</p>
<p>We also have the choice of not supplying an anchor at all. In that case, the target element uses an implicit anchor element defined in <code>position-anchor</code>. If there isn’t an implicit anchor, the function resolves to its fallback. Otherwise, it is invalid and ignored.</p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;anchor-side&gt;</summary>
<p>This argument sets which side of the anchor we want to position the target element to, e.g. the anchor’s <code>top</code>, <code>left</code>, <code>bottom</code>, <code>right</code>, etc.</p>
<p>But we have more options than that, including logical side keywords (<code>inside</code>, <code>outside</code>), logical direction arguments relative to the user’s writing mode (<code>start</code>, <code>end</code>, <code>self-start</code>, <code>self-end</code>) and, of course, <code>center</code>.</p>
<ul class="wp-block-list">
<li><code>&lt;anchor-side&gt;</code>: Resolves to the <code>&lt;length&gt;</code> of the corresponding side of the anchor element. It has physical arguments (<code>top</code>, <code>left</code>, <code>bottom</code> <code>right</code>), logical side arguments (<code>inside</code>, <code>outside</code>), logical direction arguments relative to the user’s writing mode (<code>start</code>, <code>end</code>, <code>self-start</code>, <code>self-end</code>) and the <code>center</code> argument.</li>
<li><code>&lt;percentage&gt;</code>: Refers to the position between the <code>start</code> (<code>0%</code>) and <code>end</code> (<code>100%</code>). Values below <code>0%</code> and above <code>100%</code> are allowed.</li>
</ul>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>&lt;length-percentage&gt;</summary>
<p>This argument is totally optional, so you can leave it out if you’d like. Otherwise, use it as a way of re-sizing the target elemenrt whenever it doesn’t have a valid anchor or position. It positions the target to a fixed <code>&lt;length&gt;</code> or <code>&lt;percentage&gt;</code> relative to its containing block.</p>
</details>
<p>Let’s look at examples using different types of arguments because they all do something a <em>little</em> different.</p>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using physical arguments</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380924" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-1.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>Physical arguments</strong> (<code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>) can be used to position the target regardless of the user’s writing mode. For example, we can position the <code>right</code> and <code>bottom</code> inset properties of the target at the <code>anchor(top)</code> and <code>anchor(left)</code> sides of the anchor, effectively positioning the target at the anchor’s top-left corner:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
bottom: anchor(top);
right: anchor(left);
}</code></pre>
<p></p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using logical side keywords</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380926" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-2.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>Logical side arguments</strong>&nbsp;(i.e.,&nbsp;<code>inside</code>,&nbsp;<code>outside</code>), are dependent on the inset property they are in. The&nbsp;<code>inside</code>&nbsp;argument will choose the same side as its inset property, while the&nbsp;<code>outside</code>&nbsp;argument will choose the opposite. For example:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
left: anchor(outside);
/* is the same as */
left: anchor(right);
top: anchor(inside);
/* is the same as */
top: anchor(top);
}</code></pre>
<p></p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using logical directions</summary>
<p></p>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380927" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-3.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>Logical direction arguments </strong>are dependent on two factors:</p>
<ol class="wp-block-list">
<li>The user’s writing mode: they can follow the writing mode of the containing block (<code>start</code>, <code>end</code>) or the target’s own writing mode (<code>self-start</code>, <code>self-end</code>).</li>
<li>The inset property they are used in: they will choose the same axis of their inset property.</li>
</ol>
<p>So for example, using physical inset properties in a left-to-right horizontal writing would look like this:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
left: anchor(start);
/* is the same as */
left: anchor(left);
top: anchor(end);
/* is the same as */
top: anchor(bottom);
}</code></pre>
<p>In a right-to-left writing mode, we’d do this:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
left: anchor(start);
/* is the same as */
left: anchor(right);
top: anchor(end);
/* is the same as */
top: anchor(bottom);
}</code></pre>
<p>That can quickly get confusing, so we should also use logical arguments with <a href="https://css-tricks.com/css-logical-properties-and-values/">logical inset properties</a> so the writing mode is respected in the first place:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
inset-inline-start: anchor(end);
inset-block-start: anchor(end);
}</code></pre>
<p></p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using percentage values</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380929" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-4-1.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>Percentages </strong>can be used to position the target from any point between the <code>start</code> (<code>0%</code>) and <code>end</code> (<code>100%</code> ) sides. Since percentages are relative to the user writing mode, is preferable to use them with logical inset properties.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
inset-inline-start: anchor(100%);
/* is the same as */
inset-inline-start: anchor(end);
inset-block-end: anchor(0%);
/* is the same as */
inset-block-end: anchor(start);
}</code></pre>
<p>Values smaller than <code>0%</code> and bigger than <code>100%</code> are accepted, so <code>-100%</code> will move the target towards the start and <code>200%</code> towards the end.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
inset-inline-start: anchor(200%);
inset-block-end: anchor(-100%);
}</code></pre>
<p></p>
</details>
<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Using the center keyword</summary>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?resize=1024%2C576&amp;ssl=1" alt="targets sorrounding the anchor. each with a different position" class="wp-image-380934" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-function-5.png?w=1920&amp;ssl=1 1920w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p><strong>The <code>center</code> argument</strong> is equivalent to <code>50%</code>. You could say that it’s “immune” to direction, so there is no problem if we use it with physical or logical inset properties.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-anchor: --my-anchor;
left: anchor(center);
bottom: anchor(top);
}</code></pre>
<p></p>
</details>
</div></div>
</div>
<div class="wp-block-column ticss-f036ecb3 is-layout-flow wp-block-column-is-layout-flow"><h4 class="wp-block-heading" id="-anchor-size-"><code>anchor-size()</code></h4>
<p>The <code>anchor-size()</code> function is unique in that it sizes the target element relative to the size of the anchor element. This can be super useful for ensuring a target scales in size with its anchor, particularly in responsive designs where elements tend to get shifted, re-sized, or obscured from overflowing a container.</p>
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<p>The function takes an anchor’s side and resolves to its <code>&lt;length&gt;</code>, essentially returning the anchor’s <code>width</code>, <code>height</code>, <code>inline-size</code> or <code>block-size</code>.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">anchor-size( [ &lt;anchor-element&gt; || &lt;anchor-size&gt; ]? , &lt;length-percentage&gt;? )</code></pre>
<figure class="wp-block-image size-large is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="576" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-size-function.png?resize=1024%2C576&amp;ssl=1" alt="anchor with an anchor-size() function on each side" class="wp-image-380930" style="width:550px" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-size-function.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-size-function.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-size-function.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/09/anchor-siz ... |
http://localhost:1200/css-tricks/fresh - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Fresh From the Almanac</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/fresh" rel="self" type="application/rss+xml"></atom:link>
<description>Properties, selectors, rules, and functions! - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Sat, 18 Jan 2025 06:20:30 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>@counter-style</title>
<description><p>The <code>@counter-style</code> at-rule lets you create custom list counters that can be used in the <a href="https://css-tricks.com/list-style-recipes/"><code>list-style-type</code></a> property and the <code>counter()</code> and <code>counters()</code> functions. It also allows for extending existing counter styles.</p>
<span id="more-383552"></span>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style apple-counter {
system: cyclic;
symbols: "🍎"; /* or "1F34E" */
suffix: " ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_bNbLELb" src="https://codepen.io/anon/embed/preview/bNbLELb?height=600&amp;theme-id=1&amp;slug-hash=bNbLELb&amp;default-tab=result" height="600" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed bNbLELb" title="CodePen Embed bNbLELb" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>The <code>@counter-style</code> at-rule is defined in the <a href="https://www.w3.org/TR/css-counter-styles-3/#the-counter-style-rule" rel="noopener">CSS Counter Styles Level 3</a> specification.</p>
<h3 class="wp-block-heading" id="syntax"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-syntax" aria-hidden="true" class="aal_anchor" id="aa-syntax"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Syntax</h3>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style &lt;counter-style-name&gt; {
&lt;declaration-list&gt;
}</code></pre>
<h3 class="wp-block-heading" id="arguments-and-descriptors"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-arguments-and-descriptors" aria-hidden="true" class="aal_anchor" id="aa-arguments-and-descriptors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Arguments and descriptors</h3>
<ul class="wp-block-list">
<li><strong><code>&lt;counter-style-name&gt;</code>:</strong> A case-sensitive <code>&lt;custom-ident&gt;</code> that doesn’t match any of the CSS-wide keywords, <code>none</code>, <code>inside</code> and <code>outside</code></li>
<li><strong><code>&lt;declaration-list&gt;</code>:</strong> A list of the descriptors used to define a custom counter
<ul class="wp-block-list">
<li><strong><code>system</code> (Required):</strong> Specifies which algorithm will be used to construct the counter’s string representation</li>
<li><strong><code>negative</code>:</strong> Specifies the counter representation if the counter value is negative</li>
<li><strong><code>prefix</code> (Optional):</strong> Specifies a <code>&lt;symbol&gt;</code> that will be attached <strong>before</strong> the marker representation and any negative sign</li>
<li><strong><code>suffix</code> (Optional):</strong> Specifies a <code>&lt;symbol&gt;</code> that will be attached <strong>after</strong> the marker representation and any negative sign</li>
<li><strong><code>range</code> (Optional):</strong> Specifies the range in which the custom counter is used. Counter values outside the range will drop to their <code>fallback</code> counter style.</li>
<li><strong><code>pad</code> (Optional):</strong> Specifies a minimum width all representations have to reach. Representations shorter than the minimum are padded with a <code>&lt;symbol&gt;</code>.</li>
<li><strong><code>fallback</code> (Optional):</strong> Specifies a fallback counter used whenever a counter style can’t represent a counter value</li>
<li><strong><code>symbols</code>:</strong> Specifies the symbols used by the construction <code>system</code> algorithm. It’s required unless the <code>system</code> is set to <code>additive</code> or <code>extends</code>.</li>
<li><strong><code>additive-symbols</code>:</strong> Specifies the symbols used by the construction algorithm when the <code>system</code> descriptor is set to <code>additive</code></li>
<li><strong><code>speak-as</code> (Optional):</strong> Specifies how screen readers should read the counter style</li>
</ul>
</li>
</ul>
<h4 class="wp-block-heading" id="a-note-about-naming"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-a-note-about-naming" aria-hidden="true" class="aal_anchor" id="aa-a-note-about-naming"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>A note about naming</h4>
<p>The <code>@counter-style</code> at-rule has some caveats about its naming:</p>
<ul class="wp-block-list">
<li><code>&lt;counter-style-name&gt;</code> can’t be a CSS-wide keyword (i.e., <code>initial</code>, <code>inherit</code> and <code>unset</code>) or <code>none</code>, as doing so renders the at-rule invalid.</li>
<li>Although predefined counter styles (e.g., <code>decimal</code>, <code>lower-roman</code>, <code>square</code>, etc.) are of type <code>&lt;counter-style-name&gt;</code>, trying to use them as a <code>@counter-style</code> name is also invalid.</li>
<li>Names like <code>inside</code> or <code>outside</code> are valid as counter styles names, but conflict with properties like the <a href="https://css-tricks.com/almanac/properties/l/list-style/"><code>list-style</code></a> shorthand.</li>
<li><code>@counter-style</code> at-rules are defined for the entire document. If multiple valid <code>@counter-style</code> are defined, the last one wins and abides by the CSS Cascade. Writing a new <code>@counter-style</code> with the same name replaces other instances rather than just the changed descriptors.</li>
</ul>
<h3 class="wp-block-heading" id="the-system-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-system-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-system-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>system</code> descriptor</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value: </strong><code>cyclic | numeric | alphabetic | symbolic | additive | [fixed &lt;integer&gt;?] | [ extends &lt;counter-style-name&gt; ]</code></li>
<li><strong>Initial:</strong> <code>symbolic</code></li>
</ul>
<p>The <code>system</code> descriptor sets the algorithm to construct the counter representation for each counter value. It affects whether @counter-styles uses the symbols or additive-symbols descriptors, and the minimum length of symbols needed.</p>
<h4 class="wp-block-heading" id="-cyclic-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-cyclic" aria-hidden="true" class="aal_anchor" id="aa-cyclic"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>cyclic</strong></code></h4>
<p>The <code>cyclic</code> system goes through the characters set on the <code>symbols</code> descriptors repeating them until the list is over or limited by the <code>range</code> descriptor. We can use just one character in the <code>symbols</code> to mimic a bullet list:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style bullet-example {
system: cyclic;
symbols: "⏵";
suffix: " ";
}</code></pre>
<p>Or alternate between two or more characters:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style multiple-example {
system: cyclic;
symbols: "🔸" "🔹";
suffix: " ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_vEBdmQN" src="https://codepen.io/anon/embed/preview/vEBdmQN?height=450&amp;theme-id=1&amp;slug-hash=vEBdmQN&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed vEBdmQN" title="CodePen Embed vEBdmQN" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-fixed-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-fixed" aria-hidden="true" class="aal_anchor" id="aa-fixed"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>fixed</strong></code></h4>
<p>Instead of cycling through the characters in the <code>symbols</code> descriptor, we can make those characters appear just one time using the <code>fixed</code> system. In the last example, only the first two items have a custom counter if set to <code>fixed</code>, while the others drop to their <code>fallback</code> symbol.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style multiple-example {
system: fixed;
symbols: "🔸" "🔹";
suffix: " ";
}</code></pre>
<p>We can set when the custom counters start by appending an <code>&lt;integer&gt;</code> to the <code>fixed</code> value. For example, the following custom counter starts at the fourth item:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style bullet-start-example {
system: fixed 4;
symbols: "💠";
suffix: " ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_JoPpNwQ" src="https://codepen.io/anon/embed/preview/JoPpNwQ?height=450&amp;theme-id=1&amp;slug-hash=JoPpNwQ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed JoPpNwQ" title="CodePen Embed JoPpNwQ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-numeric-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-numeric" aria-hidden="true" class="aal_anchor" id="aa-numeric"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>numeric</strong></code></h4>
<p>The <code>numeric</code> system enumerates list items using a <strong>custom positional system</strong> (base-2, base-8, base-16, etc.). Positional systems start at <code>0</code>, so the first character in <code>symbols</code> will be used as <code>0</code>, the next as <code>1</code>, and so on. Knowing this, we can make an ordered list using non-decimal numerical systems like binary:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style binary-example {
system: numeric;
symbols: "0" "1";
suffix: ". ";
}</code></pre>
<p>Or hexadecimal:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style hexadecimal-example {
system: numeric;
symbols: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F";
suffix: ". ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_raBJmEo" src="https://codepen.io/anon/embed/preview/raBJmEo?height=450&amp;theme-id=1&amp;slug-hash=raBJmEo&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed raBJmEo" title="CodePen Embed raBJmEo" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-alphabetic-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-alphabetic" aria-hidden="true" class="aal_anchor" id="aa-alphabetic"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>alphabetic</strong></code></h4>
<p>The <code>alphabetic</code> system enumerates list items using a custom <strong>alphabetical system</strong>. It’s similar to the <code>numeric</code> system but with the key difference that it doesn’t have a character for <code>0</code>, so the proceeding digits are repeated. For example, if our <code>symbols</code> are <code>A</code>, <code>B</code>, and <code>C</code>, they will wrap to <code>AA</code>, <code>AB</code>, and <code>AC</code>, then <code>BA</code>, <code>BB</code>, <code>BC</code>, and so on.</p>
<p class="is-style-explanation">Since there is no equivalent for <code>0</code> and negative values, they will drop down to their fallback symbol.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style abc-example {
system: alphabetic;
symbols: "A" "B" "C";
suffix: ". ";
}</code></pre>
<p>If we try to recreate a decimal numbering system using the <code>alphabetic</code> algorithm, we will quickly notice two things:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style decimal-example {
system: alphabetic;
symbols: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9";
suffix: ". ";
}</code></pre>
<ol class="wp-block-list">
<li>It starts at <code>0</code> since the <code>alphabetic</code> system is taking that character as <code>1</code>.</li>
<li>Instead of going from <code>9</code> to <code>10</code>, it goes to <code>00</code> since the next digits are just repeated, and then proceed as <code>01</code>, <code>02</code>, <code>03</code>, etc.</li>
</ol>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_yyBvbWq" src="https://codepen.io/anon/embed/preview/yyBvbWq?height=450&amp;theme-id=1&amp;slug-hash=yyBvbWq&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed yyBvbWq" title="CodePen Embed yyBvbWq" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-symbolic-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-symbolic" aria-hidden="true" class="aal_anchor" id="aa-symbolic"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>symbolic</strong></code></h4>
<p>The <code>symbolic</code> system goes through the characters in <code>symbols</code>, repeating them one more time each iteration. For example, if our <code>symbols</code> are <code>A</code>, <code>B</code>, and <code>C</code>, the first three items will be <code>A</code>, <code>B</code>, and <code>C</code>, respectively, and then they are doubled in the next iteration as <code>AA</code>, <code>BB</code>, and <code>CC</code>, respectively, before getting tripled as <code>AAA</code>, <code>BBB</code>, and <code>CCC</code>, and so on.</p>
<p class="is-style-explanation">Since there is no equivalent for <code>0</code> and negative values, they will drop down to their fallback symbol.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style symbolic-example {
system: symbolic;
symbols: "A" "B" "C";
suffix: ". ";
}</code></pre>
<p>In this case, our decimal representation would go from <code>9</code> to <code>00</code> (similar to <code>alphabetic</code>) but then double to <code>11</code>, <code>22</code>, <code>33</code>, and so on.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style decimal-example {
system: alphabetic;
symbols: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9";
suffix: ". ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_pvzawRQ" src="https://codepen.io/anon/embed/preview/pvzawRQ?height=450&amp;theme-id=1&amp;slug-hash=pvzawRQ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed pvzawRQ" title="CodePen Embed pvzawRQ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-additive-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-additive" aria-hidden="true" class="aal_anchor" id="aa-additive"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>additive</strong></code></h4>
<p>The <code>additive</code> system assigns characters a numerical value and adds them together to get the counter representation. You can think of the additive system as counting bills: if we have only <code>$5</code>, <code>$2</code>, and <code>$1</code> bills, we will add them together to get the desired quantity, trying to keep the number of bills used at a minimum. So to represent <code>10</code>, we will use two <code>$5</code> bills instead of ten <code>$1</code> bills.</p>
<p class="is-style-explanation">Since there is no equivalent for negative values, they will drop down to their fallback.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style bills-example {
system: additive;
additive-symbols: 5 "5️⃣", 2 "2️⃣", 1 "1️⃣";
suffix: " ";
}</code></pre>
<p class="is-style-explanation">Since we need to give each character an <code>&lt;integer&gt;</code> value, we use the <code>additive-symbols</code> instead of the <code>symbols</code>. It takes a comma-separated list of each <code>&lt;integer&gt;</code> and its equivalent <code>&lt;symbol&gt;</code>.</p>
<p>Another example would be using dice, since we can only represent up to 6 with one regular dice, we will need more to represent higher quantities:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style additive-example {
system: additive;
additive-symbols: 6 "⚅", 5 "⚄", 4 "⚃", 3 "⚂", 2 "⚁", 1 "⚀";
suffix: " ";
}</code></pre>
<p class="is-style-explanation">If we didn’t have a representation for <code>1</code>, we wouldn’t be able to represent every value so they would drop to their <code>fallback</code>.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_EaYQQPL" src="https://codepen.io/anon/embed/preview/EaYQQPL?height=450&amp;theme-id=1&amp;slug-hash=EaYQQPL&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed EaYQQPL" title="CodePen Embed EaYQQPL" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="-extends-"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-extends" aria-hidden="true" class="aal_anchor" id="aa-extends"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code><strong>extends</strong></code></h4>
<p>The <code>extends</code> system creates a custom style from another one but with modifications such as its <code>suffix</code>/<code>prefix</code> or <code>negative</code> representations. To do so, it takes a <code>&lt;counter-style-name&gt;</code> after the <code>extends</code> value. For example, we could change the <code>decimal</code> counter style default <code>suffix</code> to a closing parenthesis <code>")"</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style decimal-example {
system: extends decimal;
suffix: ") ";
}</code></pre>
<p class="is-style-explanation">Per <cite>spec</cite>, <q>If a <code>@counter-style</code> uses the <code>extends</code> system, it must not contain a <code>symbols</code> or <code>additive-symbols</code> descriptor, or else the <code>@counter-style</code> rule is invalid.</q></p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_KwPQQrZ" src="https://codepen.io/anon/embed/preview/KwPQQrZ?height=450&amp;theme-id=1&amp;slug-hash=KwPQQrZ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed KwPQQrZ" title="CodePen Embed KwPQQrZ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-negative-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-negative-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-negative-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>negative</code> descriptor</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value:</strong> <code>&lt;symbol&gt; &lt;symbol&gt;?</code></li>
<li><strong>Initial:</strong> <code>"-"</code> (hyphen-minus)</li>
</ul>
<p>The <code>negative</code> descriptor creates a custom representation for negative values. It can take one or two <code>&lt;symbol&gt;</code> arguments: The first one is prepended to the counter, and by default, it’s the <em>hyphen-minus</em> (<code>"-"</code>) character. The second one is appended to the counter. For example, using <code>"(" ")"</code> we could enclose negative representations into parenthesis <code>(2), (1), 0, 1, 2</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style enclosed-example {
system: extends decimal;
negative: "(" ")";
}</code></pre>
<p>We also can extend the initial <code>"-"</code> by keeping it as the first value:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style exclamation-example {
system: extends decimal;
negative: "-" "!";
suffix: " ";
}</code></pre>
<p>Or remove it for a custom negative symbol:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style down-example {
system: extends decimal;
negative: "🔻";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_MYgOXMR" src="https://codepen.io/anon/embed/preview/MYgOXMR?height=450&amp;theme-id=1&amp;slug-hash=MYgOXMR&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed MYgOXMR" title="CodePen Embed MYgOXMR" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-prefix-and-suffix-descriptors"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-prefix-and-suffix-descriptors" aria-hidden="true" class="aal_anchor" id="aa-the-prefix-and-suffix-descriptors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>prefix</code> and <code>suffix</code> descriptors</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value (Both):</strong> <code>&lt;symbol&gt;</code></li>
<li><strong>Initial (<code>prefix</code>): </strong><code>""</code> (the empty string)</li>
<li><strong>Initial (<code>suffix</code>):</strong> <code>"2E20"</code> (full stop followed by a space, <code>"."</code>)</li>
</ul>
<p>The <code>prefix</code> and <code>suffix</code> descriptor allows us to prepend and append, respectively, a symbol to the counter representation. We can use it to add a character at the beginning of each counter using <code>prefix</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style prefixed-example {
system: extends decimal;
prefix: "‣ ";
}</code></pre>
<p>In the end, using <code>suffix</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style suffixed-example {
system: extends decimal;
suffix: ") ";
}</code></pre>
<p>Or on both sides using both descriptors:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style both-example {
system: extends decimal;
prefix: "(";
suffix: ") ";
}</code></pre>
<p class="is-style-explanation">Per <cite>spec</cite>, prefixes and suffixes <q>are only added by the algorithm for constructing the default contents of the <code>::marker</code> pseudo-element; the prefix is not added automatically when the <code>counter()</code> or <code>counters()</code> functions are used.</q> However, this isn’t a problem since we can embed them directly into each function.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_dPbZjpR" src="https://codepen.io/anon/embed/preview/dPbZjpR?height=450&amp;theme-id=1&amp;slug-hash=dPbZjpR&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed dPbZjpR" title="CodePen Embed dPbZjpR" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-range-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-range-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-range-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>range</code> descriptor</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value:</strong> <code>[ [ &lt;integer&gt; | infinite ]{2} ]# | auto</code></li>
<li><strong>Initial:</strong> <code>auto</code></li>
</ul>
<p>The <code>range</code> descriptor defines <strong>an inclusive</strong> range in which the counter style is used. The default range (<code>auto</code>) depends on the <code>system</code> used:</p>
<ul class="wp-block-list">
<li><code>cyclic</code>, <code>numeric</code>, and <code>fixed</code> systems can range from <code>(-∞, ∞)</code>.</li>
<li><code>alphabetic</code> and <code>symbolic</code> systems have a range from <code>[1, ∞)</code>.</li>
<li><code>additive</code> systems have a range from <code>[0, <code>∞</code>)</code>.</li>
<li><code>extends</code> systems use the <code>range</code> of the extended counter style.</li>
</ul>
<p>We can define a bounded range by writing one <code>&lt;integer&gt;</code> next to another. For example, a range of <code>2 5</code> affects elements 2, 3, 4, and 5:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style bounded-example {
system: cyclic;
symbols: "‣";
suffix: " ";
range: 2 5;
}</code></pre>
<p>On the other hand, using the <code>infinite</code> value, we can unbound the range to one side. For example, we could write <code>infinite 5</code> so all items up to 5 ([…], 3, 4 5) have a counter style:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style unbounded-r-example {
system: alphabetic;
symbols: "A" "B" "C";
suffix: ". ";
range: infinite 5;
}</code></pre>
<p>Alternatively, we could write <code>5 infinite</code> so that all items starting from 5 (5, 6, 7…) have a custom counter style:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style unbounded-l-example {
system: numeric;
symbols: "0" "1" "2";
suffix: ". ";
range: 5 infinite;
}</code></pre>
<p>The <code>range</code> descriptor accepts a comma-separated list, so multiple intervals are accepted. For example, setting the <code>range</code> to <code>1 3, 6 7</code> affects items 1, 2, 3 and 6, 7 in the list:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style multiple-example {
system: extends upper-roman;
suffix: ") ";
range: 1 3, 6 7;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_wBwpodd" src="https://codepen.io/anon/embed/preview/wBwpodd?height=450&amp;theme-id=1&amp;slug-hash=wBwpodd&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed wBwpodd" title="CodePen Embed wBwpodd" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-pad-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-pad-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-pad-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>pad</code> descriptor</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value:</strong> <code>&lt;integer [0,∞]&gt; &amp;&amp; &lt;symbol&gt;</code></li>
<li><strong>Initial:</strong> <code>0 ""</code></li>
</ul>
<p>Some counters may need a minimal amount of width for each counter. This can be achieved by padding the counter with a specific character. For example, a zero-padded counter style would pad counters with leading zeros when needed (e.g. <code>001, 050, 200, etc</code>). We can achieve this effect using the <code>pad</code> descriptor which takes an <code>&lt;integer&gt;</code> that represents the minimum width for the counter and a <code>&lt;symbol&gt;</code> to pad it. For example, our zero-padded example would look like the following:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style zero-padded-example {
system: extends decimal;
pad: 3 "0";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_jENYVeK" src="https://codepen.io/anon/embed/preview/jENYVeK?height=450&amp;theme-id=1&amp;slug-hash=jENYVeK&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed jENYVeK" title="CodePen Embed jENYVeK" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-fallback-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-fallback-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-fallback-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>fallback</code> descriptor</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value:</strong> <code>&lt;counter-style-name&gt;</code></li>
<li><strong>Initial:</strong> <code>decimal</code></li>
</ul>
<p>Sometimes counter styles can’t represent certain counter values: <code>alphabetic</code> and <code>symbolic</code> systems can’t represent zero and negative values; depending on the available <code>additive-symbols</code>, <code>additive</code> systems may not represent all values; and <code>fixed</code> systems or systems with a defined <code>range</code> only represent certain values.</p>
<p>In short, sometimes a system needs to fall back to another counter style. The <code>fallback </code>descriptor allows you to define which counter style should be used as a fallback. We can fall back to a predefined counter style. For example, the following counter style is <code>fixed</code> and will fallback to <code>lower-roman</code> after the sixth item:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style predefined-example {
system: fixed;
symbols: "⚀" "⚁" "⚂" "⚃" "⚄" "⚅";
fallback: lower-roman;
}</code></pre>
<p>We can also use a custom counter style as another counter’s <code>fallback</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style custom-fallback {
system: additive;
additive-symbols: 4 "::", 3 ":.", 2 ":", 1 ".";
}
@counter-style custom-example {
system: fixed;
symbols: "⚀" "⚁" "⚂" "⚃" "⚄" "⚅";
suffix: " ";
fallback: custom-fallback;
}</code></pre>
<p>Fallbacks can be circular, meaning that “counter style A” <code>fallback</code> could be “counter style B” and vice versa. According to the spec, this is intentional:</p>
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>For example, if an author desires a counter style with significantly different representations for even and odd counter values, they may find it easiest to define one style that can only represent odd values and one that can only represent even values, and specify each as the fallback for the other one.</p>
</blockquote>
<p>However, I couldn’t find a way to implement this behavior using circular fallbacks. Luckily, it can be done just using one counter style that is only able to represent even styles and can fall back to one that represents each counter value:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style odd-style {
system: additive;
additive-symbols: 2 "⁑", 1 "*";
}
@counter-style even-style {
system: additive;
additive-symbols: 2 ":";
suffix: " ";
fallback: odd-style;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_MYgrbNL" src="https://codepen.io/anon/embed/preview/MYgrbNL?height=450&amp;theme-id=1&amp;slug-hash=MYgrbNL&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed MYgrbNL" title="CodePen Embed MYgrbNL" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-symbols-descriptors"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-symbols-descriptors" aria-hidden="true" class="aal_anchor" id="aa-the-symbols-descriptors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>symbols</code> descriptors</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value: </strong><code>&lt;symbol&gt;+</code></li>
<li><strong>Initial:</strong> <code>n/a</code></li>
</ul>
<p>The <code>symbols</code> descriptor defines a space separated <code>&lt;symbol&gt;</code> list that the <code>system</code> algorithm will use to construct each counter representation, except the <code>additive</code> and <code>extends</code> systems. The exact definition of a <code>&lt;symbol&gt;</code> is the following:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;symbol&gt; = &lt;string&gt; | &lt;image&gt; | &lt;custom-ident&gt;</code></pre>
<p class="is-style-explanation">Support for <code>&lt;image&gt;</code> is scarce.</p>
<p>So, you may see characters written as strings:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style string-example {
system: cyclic;
symbols: "⁘" "⁙";
suffix: " ";
}</code></pre>
<p>Or written directly as custom idents.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style ident-example {
system: numeric;
symbols: ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉;
suffix: " ";
}</code></pre>
<p>Or both together:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style both-example {
system: alphabetic;
symbols: A "B" C;
suffix: " ";
}</code></pre>
<p>However, what is valid as a string isn’t necessarily valid as a custom ident. For example, starting an ident with a number or using ASCII non-letters (e.g. <code>*</code>) will invalidate the counter style, so it’s necessary to escape them using a backslash (<code></code>) or simply enclose them into a string:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style escaped-example {
system: cyclic;
symbols: *; /* or "*" */
suffix: " ";
}</code></pre>
<p>Also, we can use Unicode characters by writing a backslash (<code></code>) followed by their identifier. This can be easily achieved using strings:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style unicode-string-example {
system: cyclic;
symbols: "2217""2218";
suffix: " ";
}</code></pre>
<p>In the case of a custom ident, backslash escapes reserve the following space for another digit, so we need two spaces between Unicode characters.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style unicode-ident-example {
system: cyclic;
symbols: 2234 2235;
suffix: " ";
}</code></pre>
<p>For these little caveats, I recommend sticking to strings for <code>symbols</code> and <code>additive-symbols</code>.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_jENYvyP" src="https://codepen.io/anon/embed/preview/jENYvyP?height=450&amp;theme-id=1&amp;slug-hash=jENYvyP&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed jENYvyP" title="CodePen Embed jENYvyP" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-additive-symbols-descriptors"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-additive-symbols-descriptors" aria-hidden="true" class="aal_anchor" id="aa-the-additive-symbols-descriptors"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The <code>additive-symbols</code> descriptors</h3>
<ul class="wp-block-list is-style-almanac-list">
<li><strong>Value:</strong> <code>[ &lt;integer [0,∞]&gt; &amp;&amp; &lt;symbol&gt; ]#</code></li>
<li><strong>Initial:</strong> N/A</li>
</ul>
<p>The <code>additive-symbols</code> descriptors defines a comma-separated list composed of an <code>&lt;integer&gt;</code> and a <code>&lt;symbol&gt;</code> that will be used by the <code>additive</code> algorithm, ordered from highest to lowest. It has the same caveats regarding the <code>&lt;symbol&gt;</code> value as the <code>symbols</code> descriptor, so I also recommend using only strings:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">@counter-style string-example {
system: additive;
additive-symbols: 5 "⁙", 4 "⁘", 3 "⁖", 2 "‥", 1 "․";
suffix: " ";
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_dPbJqxr" src="https://codepen.io/anon/embed/preview/dPbJqxr?height=450&amp;theme-id=1&amp;slug-hash=dPbJqxr&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed dPbJqxr" title="CodePen Embed dPbJqxr" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="the-speak-as-descriptor"><a href="https://css-tricks.com/almanac/rules/c/counter-style/#aa-the-speak-as-descriptor" aria-hidden="true" class="aal_anchor" id="aa-the-speak-as-descriptor"><svg aria-hidden="true" class="aal_svg" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0 ... |
http://localhost:1200/css-tricks/popular - Success ✔️<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Popular this month</title>
<link>https://css-tricks.com</link>
<atom:link href="http://localhost:1200/css-tricks/popular" rel="self" type="application/rss+xml"></atom:link>
<description>Popular CSS articles this month - Powered by RSSHub</description>
<generator>RSSHub</generator>
<webMaster>[email protected] (RSSHub)</webMaster>
<language>en</language>
<lastBuildDate>Sat, 18 Jan 2025 06:20:32 GMT</lastBuildDate>
<ttl>5</ttl>
<item>
<title>A CSS Wishlist for 2025</title>
<description><p>2024 has been one of the greatest years for CSS: <a href="https://css-tricks.com/tag/view-transitions/">cross-document view transitions</a>, <a href="https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/">scroll-driven animations</a>, <a href="https://css-tricks.com/css-anchor-positioning-guide/">anchor positioning</a>, <a href="https://css-tricks.com/transitioning-to-auto-height/">animate to <code>height: auto</code></a>, and many others. It seems out of touch to ask, but what else do we want from CSS? Well, many things!</p>
<p>We put our heads together and came up with a few ideas… including several of yours.</p>
<!--more-->
<h3 class="wp-block-heading" id="geoff-s-wishlist">Geoff’s wishlist</h3>
<p>I’m of the mind that we already have a BUNCH of wonderful CSS goodies these days. We have so many wonderful — and new! — things that I’m still wrapping my head around many of them.</p>
<p>But! There’s always room for one more good thing, right? Or maybe room for <em>four</em> new things. If I could ask for any new CSS features, these are the ones I’d go for.</p>
<h4 class="wp-block-heading" id="if-">1. A conditional <code>if()</code> statement</h4>
<p>It’s coming! Or it’s already here if you consider that the CSS Working Group (CSSWG)&nbsp;<a href="https://github.com/w3c/csswg-drafts/issues/10064#issuecomment-2165157958" rel="noopener">resolved to add an&nbsp;<code>if()</code>&nbsp;conditional</a>&nbsp;to the CSS Values Module Level 5 specification. That’s a big step forward, even if it takes a year or two (or more?!) to get a formal definition and make its way into browsers.</p>
<p>My understanding about <code>if()</code> is that it’s a key component for achieving <a href="https://css-tricks.com/css-container-queries/#aa-container-style-queries">Container Style Queries</a>, which is what I ultimately want from this. Being able to apply styles conditionally based on the styles of another element is the white whale of CSS, so to speak. We can already style an element based on what other elements it <code>:has()</code> so this would expand that magic to include conditional styles as well.</p>
<h4 class="wp-block-heading" id="mixins">2. CSS mixins</h4>
<p>This is more of a “nice-to-have” feature because I feel its squarely in CSS Preprocessor Territory and believe it’s nice to have some tooling for light abstractions, such as writing functions or mixins in CSS. But I certainly wouldn’t say “no” to having mixins baked right into CSS if someone was offering it to me. That might be the straw that breaks the CSS preprocessor back and allows me to write plain CSS 100% of the time because right now I tend to reach for Sass when I need a mixin or function.</p>
<p><a href="https://css-tricks.com/css-functions-and-mixins-module-notes/">I wrote up a bunch of notes about the mixins proposal and its initial draft in the specifications</a> to give you an idea of why I’d want this feature.</p>
<h4 class="wp-block-heading" id="-inline-comments">3. <code>// inline comments</code></h4>
<p>Yes, please! It’s a minor developer convenience that brings CSS up to par with writing comments in other languages. I’m pretty sure that writing JavaScript comments in my CSS should be in <a href="https://css-tricks.com/my-dumbest-css-mistakes/">my list of dumbest CSS mistakes</a> (even if I didn’t put it in there).</p>
<h4 class="wp-block-heading" id="font-size-fit">4. <code>font-size: fit</code></h4>
<p>I just hate doing math, alright?! Sometimes I just want a word or short heading sized to the container it’s in. <a href="https://css-tricks.com/simplified-fluid-typography/">We can use things like <code>clamp()</code> for fluid typesetting</a>, but again, that’s math I can’t be bothered with. You might think there’s a possible solution with Container Queries and <a href="https://css-tricks.com/css-container-queries/#aa-container-length-units">using container query units</a> for the <code><a href="https://css-tricks.com/almanac/properties/f/font-size/">font-size</a></code> but that doesn’t work any better than <a href="https://css-tricks.com/css-length-units/#aa-relative-units">viewport units</a>.</p>
<h3 class="wp-block-heading" id="ryans-wishlist">Ryan’s wishlist</h3>
<p>I’m just a simple, small-town CSS developer, and I’m quite satisfied with all the new features coming to browsers over the past few years, what more could I ask for?</p>
<h4 class="wp-block-heading" id="anchor-positioning-in-more-browsers">5. Anchor positioning in more browsers!</h4>
<p>I don’t need anymore convincing on CSS anchor positioning, <em>I’m sold!</em> After spending much of the month of November <a href="https://css-tricks.com/one-of-those-onboarding-uis-with-anchor-positioning/">learning how it works</a>, I went into December knowing I won’t <em>really</em> get to use it for a while. </p>
<p>As we close out 2024, only Chromium-based browsers have support, and fallbacks and progressive enhancements are not easy, unfortunately. There is a polyfill available (which is awesome), however, that does mean adding another chunk of JavaScript, contrasting what anchor positioning solves.</p>
<p>I’m patient though, I waited a long time for <code>:has</code> to come to browsers, which has been “<em>newly available</em>” in Baseline for a year now (can you believe it?).</p>
<h4 class="wp-block-heading" id="a-way-to-move-an-element-to-the-top-layer-without-popover-would-be-nice">6. Promoting elements to the <code>#top-layer</code> <em>without</em> popover?</h4>
<p>I like anchor positioning, I like popovers, and they go really well together!</p>
<p>The neat thing with popovers is how they appear in the <code>#top-layer</code>, so you get to avoid stacking issues related to <code>z-index</code>. This is probably all most would need with it, but having some other way to move an element there would be interesting. Also, now that I know that the <code>#top-layer</code> exists, I want to do <em>more</em> with it — I want to know what’s up there. <em>What’s really going on?</em></p>
<p>Well, I probably should have started at the spec. As it turns out, the <a href="https://drafts.csswg.org/css-position-4/#top-layer" rel="noopener">CSS Position Layout Module Level 4</a> draft talks about the <code>#top-layer</code>, what it’s useful for, and ways to approach styling elements contained within it. Interestingly, the <code>#top-layer</code> is controlled by the user agent and seems to be a byproduct of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API" rel="noopener">Fullscreen API</a>.</p>
<p>Dialogs and popovers are the way to go for now but, optimistically speaking, these features existing <em>might</em> mean it’s possible to promote elements to the <code>#top-layer</code> in future ways. This very well may be a coyote/roadrunner-type situation, as I’m not quite sure what I’d do with it once I get it.</p>
<h4 class="wp-block-heading" id="set-layers-from-a-link-tag">7. Adding a layer attribute to <code>&lt;link&gt;</code> tags</h4>
<p>Personally speaking, <a href="https://css-tricks.com/css-cascade-layers/">Cascade Layers</a> have changed how I write CSS. One thing I think would be ace is if we could include a <code>layer</code> attribute on a <code>&lt;link&gt;</code> tag. Imagine being able to include a CSS reset in your project like:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;link rel="stylesheet" href="https://cdn.com/some/reset.css" layer="reset"&gt;</code></pre>
<p>Or, depending on the page visited, dynamically add parts of CSS, blended into your cascade layers:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;!--
Global styles with layers defined, such as:
@layer reset, typography, components, utilities;
--&gt;
&lt;link rel="stylesheet" href="/styles/main.css"&gt;
&lt;!-- Add only to pages using card components --&gt;
&lt;link rel="stylesheet" href="/components/card.css" layer="components"&gt;</code></pre>
<p>This feature was <a href="https://github.com/w3c/csswg-drafts/issues/5853" rel="noopener">proposed over on the CSSWG’s repo</a>, and like most things in life: <em>it’s complicated</em>. </p>
<p>Browsers are especially finicky with attributes they don’t know, plus definite concerns around handling fallbacks. The topic was also brought over to the W3C Technical Architecture Group (TAG) for <a href="https://css-tricks.com/wp-admin/post.php?post=383249&amp;action=edit">discussion as well</a>, so there’s still hope!</p>
<h3 class="wp-block-heading" id="juandi-s-wishlist">Juandi’s Wishlist</h3>
<p>I must admit this, I wasn’t around when the web was wild and people had hit counters. In fact, I think I am pretty young compared to your average web <em>connoisseur</em>. While I do know how to make a layout using <code>float</code> (the first web course I picked up was <em>pretty</em> outdated), I didn’t have to suffer long before using things like Flexbox or CSS Grid and never grinded my teeth against IE and browser support.</p>
<p>So, the following wishes may seem like petty requests compared to the really necessary features the web needed in the past — or even some in the present. Regardless, here are my three petty requests I would wish to see in 2025:</p>
<h4 class="wp-block-heading" id="a-way-to-get-the-children-count-and-index-as-an-integer-">8. Get the children count and index as an integer</h4>
<p>This is one of those things that you swear it should already be possible with just CSS. The situation is the following: I find myself wanting to know the index of an element between its siblings or the total number of children. I can’t use the <code>counter()</code> function since sometimes I need an integer instead of a string. The current approach is either hardcoding an index on the HTML:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;ul&gt;
&lt;li style="--index: 0"&gt;Milk&lt;/li&gt;
&lt;li style="--index: 1"&gt;Eggs&lt;/li&gt;
&lt;li style="--index: 2"&gt;Cheese&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>Or alternatively, write each index in CSS:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">li:nth-child(1) { --index: 0; }
li:nth-child(2) { --index: 1; }
li:nth-child(3) { --index: 2; }</code></pre>
<p>Either way, I always leave with the feeling that it should be easier to reference this number; the browser already has this info, it’s just a matter of exposing it to authors. It would make prettier and cleaner code for staggering animations, or simply changing the styles based on the total count.</p>
<p>Luckily, there is a already proposal in Working Draft for <a href="https://github.com/w3c/csswg-drafts/issues/4559" rel="noopener"><code>sibling-count()</code> and <code>sibling-index()</code></a> functions. While the syntax may change, I do hope to hear more about them in 2025.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">ul &gt; li {
background-color: hsl(sibling-count() 50% 50%);
}
ul &gt; li {
transition-delay: calc(sibling-index() * 500ms);
}</code></pre>
<h4 class="wp-block-heading" id="a-way-to-balance-flex-wrap-">9. A way to balance <code>flex-wrap</code></h4>
<p>I’m stealing this one from <a href="https://nerdy.dev/css-wishlist-2025#flex-wrap-balance" rel="noopener">Adam Argyle</a>, but I do wish for a better way to balance <code>flex-wrap</code> layouts. When elements wrap one by one as their container shrinks, they either are left alone with empty space (which I don’t dislike) or grow to fill it (which hurts my soul):</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?resize=1920%2C1080&amp;ssl=1" alt="Flex Wrap leaving empty space or filling it completely" class="wp-image-383259" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-bad-example.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>I wish for a more native way of balancing wrapping elements:</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?resize=1920%2C1080&amp;ssl=1" alt="Flex wrap balancing elements" class="wp-image-383260" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/flex-wrap-good-example.png.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>It’s definitely annoying.</p>
<h4 class="wp-block-heading" id="an-easier-way-to-read-research-csswg-issues">10. An easier way to read/research CSSWG discussions</h4>
<p>I am a big fan of the CSSWG and everything they do, so I spent a lot of time reading their working drafts, GitHub issues, or notes about their meetings. However, as much as I love jumping from link to link in their GitHub, it can be hard to find all the related issues to a specific discussion.</p>
<p>I think this raises the barrier of entry to giving your opinion on some topics. If you want to participate in an issue, you should have the big picture of all the discussion (what has been said, why some things don’t work, others to consider, etc) but it’s usually scattered across several issues or meetings. While issues can be lengthy, that isn’t the problem (I love reading them), but rather not knowing part of a discussion existed somewhere in the first place.</p>
<p>So, while it isn’t directly a CSS wish, I wish there was an easier way to get the full picture of the discussion before jumping in.</p>
<h3 class="wp-block-heading" id="whats-on-your-wishlist">What’s on your wishlist?</h3>
<p>We asked! You answered! Here are a few choice selections from the crowd:</p>
<ul class="wp-block-list">
<li>Rotate direct <code>background-images</code>, like <code>background-rotate: 180deg</code></li>
<li>CSS <code>random()</code>, with params for <code>range</code>, <code>spread</code>, and <code>type</code></li>
<li>A CSS anchor position mode that allows targeting the mouse cursor, pointer, or touch point positions</li>
<li>A string selector to query a certain word in a block of text and apply styling every time that word occurs</li>
<li>A native <code>.visually-hidden</code> class.</li>
<li><code>position: sticky</code> with a <code>:stuck</code> pseudo</li>
</ul>
<h3 class="wp-block-heading" id="and-a-bigger-wish-">Wishing you a great 2025…</h3>
<p>CSS-Tricks trajectory hasn’t been the most smooth these last years, so our biggest wish for 2025 is to keep writing and sparking discussions about the web. Happy 2025! </p>
</description>
<link>https://css-tricks.com/a-css-wishlist-for-2025/</link>
<guid isPermaLink="false">https://css-tricks.com/a-css-wishlist-for-2025/</guid>
<pubDate>Mon, 23 Dec 2024 07:07:41 GMT</pubDate>
<author>Juan Diego Rodríguez</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2019/08/css-sparkle-1.png" type="image/jpeg"></enclosure>
<category>opinion</category>
</item>
<item>
<title>Yet Another Anchor Positioning Quirk</title>
<description><p>I strongly believe Anchor Positioning will go down as one of the greatest additions to CSS. It may not be as game-changing as Flexbox or Grid, but it does fill a positioning gap that has been missing for decades. As awesome as I think it is,&nbsp;<a href="https://css-tricks.com/anchor-positioning-quirks/">CSS Anchor Positioning has a lot of quirks</a>, some of which are the product of its novelty and others due to its unique way of working. Today, I want to bring you yet another Anchor Positioning quirk that has&nbsp;bugged me since I first saw it.</p>
<!--more-->
<h3 class="wp-block-heading" id="the-inception">The inception</h3>
<p>It all started a month ago when I was reading about what other people have made using Anchor Positioning, specifically this post by <a href="https://css-tricks.com/author/afiftemani/">Temani Afif</a> about <a href="https://frontendmasters.com/blog/custom-range-slider-using-anchor-positioning-scroll-driven-animations/" rel="noopener">“Anchor Positioning &amp; Scroll-Driven Animations.”</a> I strongly encourage you to read it and find out what caught my eye there. Combining Anchor Positioning and <a href="https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/">Scroll-Driven Animation</a>, he makes a range slider that changes colors while it progresses.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_JjqNEbZ" src="https://codepen.io/anon/embed/JjqNEbZ?height=450&amp;theme-id=1&amp;slug-hash=JjqNEbZ&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed JjqNEbZ" title="CodePen Embed JjqNEbZ" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Amazing by itself, but it’s interesting that he is using two target elements with the same anchor name, each attached to its corresponding anchor, just like magic. If this doesn’t seem as interesting as it looks, we should then briefly recap how Anchor Positioning works.</p>
<h3 class="wp-block-heading" id="anchor-positioning-and-the-anchor-scope-property">CSS Anchor Positioning and the <code>anchor-scope</code> property</h3>
<p class="is-style-explanation">See our complete <a href="https://css-tricks.com/css-anchor-positioning-guide/">CSS Anchor Positioning Guide</a> for a comprehensive deep dive.</p>
<p>Anchor Positioning brings two new concepts to CSS, an <em>anchor</em> element and a <em>target</em> element. The anchor is the element used as a reference for positioning other elements, hence the anchor name. While the target is an absolutely-positioned element placed relative to one or more anchors.</p>
<p>An anchor and a target can be almost every element, so you can think of them as just two <code>div</code> sitting next to each other:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div class="anchor"&gt;anchor&lt;/div&gt;
&lt;div class="target"&gt;target&lt;/div&gt;</code></pre>
<p>To start, we first have to register the anchor element in CSS using the <a href="https://css-tricks.com/almanac/properties/a/anchor-name/"><code>anchor-name</code></a> property:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.anchor {
anchor-name: --my-anchor;
}</code></pre>
<p>And the <a href="https://css-tricks.com/almanac/properties/p/position-anchor/"><code>position-anchor</code></a> property on an absolutely-positioned element attaches it to an anchor of the same name. However, to move the target around the anchor we need the <a href="https://css-tricks.com/almanac/properties/p/position-area/"><code>position-area</code></a> property.</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">.target {
position: absolute;
position-anchor: --my-anchor;
position-area: top right;
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_oNKavLV" src="https://codepen.io/anon/embed/preview/oNKavLV?height=450&amp;theme-id=1&amp;slug-hash=oNKavLV&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed oNKavLV" title="CodePen Embed oNKavLV" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>This works great, but things get complicated if we change our markup to include more anchors and targets:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;ul&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 1&lt;/div&gt;
&lt;div class="target"&gt;target 1&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 2&lt;/div&gt;
&lt;div class="target"&gt;target 2&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div class="anchor"&gt;anchor 3&lt;/div&gt;
&lt;div class="target"&gt;target 3&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>Instead of each target attaching to its closest anchor, they all pile up at the last registered anchor in the DOM.</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_BagXMNv" src="https://codepen.io/anon/embed/preview/BagXMNv?height=450&amp;theme-id=1&amp;slug-hash=BagXMNv&amp;default-tab=html,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed BagXMNv" title="CodePen Embed BagXMNv" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>The <a href="https://css-tricks.com/almanac/properties/a/anchor-scope/#aa-why-we-need-anchor-scope"><code>anchor-scope</code></a> property was introduced in Chrome 131 as an answer to this issue. It limits the scope of anchors to a subtree so that each target attaches correctly. However, I don’t want to focus on this property, because what initially caught my attention was that <strong>Temani didn’t use it</strong>. For some reason, they all attached correctly, again, like magic.</p>
<h3 class="wp-block-heading" id="what-s-happening-">What’s happening?</h3>
<p>Targets usually attach to the last anchor on the DOM instead of their closest anchor, but in our first example, we saw two anchors with the same <code>anchor-name</code> and their corresponding targets attached. All this without the <code>anchor-scope</code> property. What’s happening?</p>
<p>Two words: <strong>Containing Block</strong>.</p>
<p>Something to know about Anchor Positioning is that it relies a lot on how an element’s containing block is built. This isn’t something inherently from Anchor Positioning but from absolute positioning. Absolute elements are positioned relative to their containing block, and inset properties like <code>top: 0px</code>, <code>left: 30px</code> or <code>inset: 1rem</code> are just moving an element around its containing block boundaries, creating what’s called the <strong><a href="https://www.w3.org/TR/css-position-3/#resolving-insets" rel="noopener">inset-modified containing block</a></strong>.</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1920%2C1080&amp;ssl=1" alt="An element being shrunk by its inset-modified containing block" class="wp-image-382897" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-example.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>A target attached to an anchor isn’t any different, and what the <code>position-area</code> property does under the table is change the target’s inset-modified containing block so it is right next to the anchor.</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1920%2C1080&amp;ssl=1" alt="A target element inset-modified containing block shrunk to be in the top left corner of an anchor" class="wp-image-382898" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/inset-modified-containing-block-target.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Usually, the containing block of an absolutely-positioned element is the whole viewport, but it can be changed by any ancestor with a position other than <code>static</code> (usually <code>relative</code>). Temani takes advantage of this fact and creates a new containing block for each slider, so they can only be attached to their corresponding anchors. If you snoop around the code, you can find it at the beginning:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">label {
position: relative;
/* No, It's not useless so don't remove it (or remove it and see what happens) */
}</code></pre>
<p>If we use this tactic on our previous examples, suddenly they are all correctly attached!</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_zxOvNGE" src="https://codepen.io/anon/embed/preview/zxOvNGE?height=450&amp;theme-id=1&amp;slug-hash=zxOvNGE&amp;default-tab=css,result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed zxOvNGE" title="CodePen Embed zxOvNGE" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h3 class="wp-block-heading" id="yet-another-quirk">Yet another quirk</h3>
<p>We didn’t need to use the <code><a href="https://css-tricks.com/almanac/properties/a/anchor-scope/">anchor-scope</a></code> property to attach each anchor to its respective target, but instead took advantage of how the containing block of absolute elements is computed. However, there is yet another approach, one that doesn’t need any extra bits of code.</p>
<p>This occurred to me when I was also experimenting with <a href="https://css-tricks.com/popping-comments-with-css-anchor-positioning-and-view-driven-animations/">Scroll-Driven Animations and Anchor Positioning</a> and trying to attach text-bubble footnotes on the side of a post, like the following:</p>
<figure class="wp-block-image size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1920" height="1080" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1920%2C1080&amp;ssl=1" alt="A blog post body with paragraphs, the paragraphs have footnotes attached on the sides" class="wp-image-382899" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?w=1920&amp;ssl=1 1920w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2024/12/moving-anchors-in-one-direction.png?resize=1536%2C864&amp;ssl=1 1536w" sizes="auto, (min-width: 735px) 864px, 96vw" referrerpolicy="no-referrer"></figure>
<p>Logically, each footnote would be a target, but the choice of an anchor is a little more tricky. I initially thought that each paragraph would work as an anchor, but that would mean having more than one anchor with the same <code>anchor-name</code>. The result: all the targets would pile up at the last anchor:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_jENbBNa" src="https://codepen.io/anon/embed/preview/jENbBNa?height=450&amp;theme-id=1&amp;slug-hash=jENbBNa&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed jENbBNa" title="CodePen Embed jENbBNa" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>This could be solved using our prior approach of creating a new containing block for each note. However, there is another route we can take, what I call the reductionist method. The problem comes when there is more than one anchor with the same <code>anchor-name</code>, so we will reduce the number of anchors to one, using an element that could work as the common anchor for all targets.</p>
<p>In this case, we just want to position each target on the sides of the post so we can use the entire body of the post as an anchor, and since each target is naturally aligned on the vertical axis, what’s left is to move them along the horizontal axis:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_oNKqwgy" src="https://codepen.io/anon/embed/preview/oNKqwgy?height=450&amp;theme-id=1&amp;slug-hash=oNKqwgy&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed oNKqwgy" title="CodePen Embed oNKqwgy" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>You can better check how it was done on the original post!</p>
<h3 class="wp-block-heading" id="conclusion">Conclusion</h3>
<baseline-status class="wp-block-css-tricks-baseline-status" featureid="anchor-positioning"></baseline-status>
<p>The <code>anchor-scope</code> may be the most recent CSS property to be shipped to a browser (so far, just in Chrome 131+), so we can’t expect its support to be something out of this world. And while I would love to use it every now and there, it will remain bound to short demos for a while. This isn’t a reason to limit the use of other Anchor Positioning properties, which are supported in Chrome 125 onwards (and let’s hope in other browsers in the near future), so I hope these little quirks can help you to keep using Anchor Positioning without any fear.</p>
</description>
<link>https://css-tricks.com/yet-another-anchor-positioning-quirk/</link>
<guid isPermaLink="false">https://css-tricks.com/yet-another-anchor-positioning-quirk/</guid>
<pubDate>Mon, 09 Dec 2024 08:54:00 GMT</pubDate>
<author>Juan Diego Rodríguez</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2024/12/Yet-Another-Anchor-Positioning-Quirk.png" type="image/jpeg"></enclosure>
<category>anchor positioning</category>
</item>
<item>
<title>The Law of Diminishing Returns</title>
<description><p>Some animation can <a href="https://css-tricks.com/making-css-animations-feel-natural/">make things feel natural</a>. Too many animations <a href="https://css-tricks.com/newsletter/230-animate-everything-by-1/">becomes distracting</a>.</p>
<p>Some line spacing can <a href="https://css-tricks.com/how-to-tame-line-height-in-css/">help legibility</a>. Too much <a href="https://css-tricks.com/equilateral-triangle-perfect-paragraph/">hurts it</a>.</p>
<p>Some alt text is <a href="https://css-tricks.com/alt-text-not-always-needed/">contextual</a>. Too much alt text is <a href="https://css-tricks.com/just-how-long-should-alt-text-be/">noise</a>.</p>
<p>Some padding feels comfy. Too much padding <a href="https://codepen.io/geoffgraham/pen/OPLymod?editors=1100" rel="noopener">feels exposed</a>.</p>
<p>Some specificity is <a href="https://css-tricks.com/strategies-keeping-css-specificity-low/">manageable</a>. Too much specificity is <a href="https://css-tricks.com/specifics-on-css-specificity/">untenable</a>.</p>
<p>Some technical debt is <a href="https://css-tricks.com/defining-and-dealing-with-technical-debt/">healthy</a>. Too much of it becomes a <a href="https://css-tricks.com/technical-debt-is-like-tetris/">burden</a>.</p>
<p>Some corner rounding is <a href="https://css-tricks.com/tabs-with-round-out-borders/">classy</a>. Too much is <a href="https://css-tricks.com/what-happens-when-border-radii-overlap/">just a circle</a>.</p>
<p>Some breakpoints are <a href="https://css-tricks.com/fluid-everything-else/">fluid</a>. Too many of them becomes <a href="https://css-tricks.com/snippets/css/media-queries-for-standard-devices/">adaptive</a>.</p>
<p>Some margin <a href="https://css-tricks.com/component-spacing-design-system/">adds breathing room</a>. Too much margin <a href="https://css-tricks.com/what-you-should-know-about-collapsing-margins/">collapses things</a>.</p>
<p>Some images <a href="https://css-tricks.com/your-image-is-probably-not-decorative/">add context</a>. Too many images takes a <a href="https://httparchive.org/reports/state-of-images?lens=top1m&amp;start=2018_11_01&amp;end=latest&amp;view=list" rel="noopener">long time to download</a> (and <a href="https://css-tricks.com/reduce-your-websites-environmental-impact-with-a-carbon-budget/">impacts the environment</a>).</p>
<p>Some JavaScript <a href="https://css-tricks.com/embrace-the-platform/">enhances interactions</a>. Too much becomes a <a href="https://www.smashingmagazine.com/2023/10/speedcurve-fight-main-thread/" rel="noopener">bottleneck</a>.</p>
<p>A font pairing creates a <a href="https://css-tricks.com/sites-for-browsing-type-pairings/">typographic system</a>. Too many pairings creates a <a href="https://pimpmytype.com/pairing-fonts/" rel="noopener">visual distraction</a>.</p>
<p>Some utility classes <a href="https://css-tricks.com/building-a-scalable-css-architecture-with-bem-and-utility-classes/">come in handy</a>. Too many <a href="https://css-tricks.com/css-utility-classes-separation-concerns/">eliminates a separation of concerns</a>.</p>
<p>Some data <a href="https://css-tricks.com/writing-feature-requirements/">helps make decisions</a>. Too much data <a href="https://robinrendle.com/notes/vibe-driven-development/" rel="noopener">kills the vibe</a>.</p>
<p>Some AI can help <a href="https://github.blog/news-insights/research/research-how-github-copilot-helps-improve-developer-productivity/" rel="noopener">write the boring parts of code</a>. Too much puts <a href="https://www.gitclear.com/coding_on_copilot_data_shows_ais_downward_pressure_on_code_quality" rel="noopener">downward pressure on code quality</a>.</p>
<p>Some SEO <a href="https://css-tricks.com/common-sense-seo-checklist/">improves search ranking</a>. Too much mutes <a href="https://css-tricks.com/make-it-personal/">the human voice</a>.</p>
<p>Some testing provides <a href="https://css-tricks.com/front-end-testing-is-for-everyone/">good coverage</a>. Too much testing <a href="https://css-tricks.com/lessons-learned-from-a-year-of-testing-the-web-platform/">requires its own maintenance</a>.</p>
<p>A few colors establish a <a href="https://css-tricks.com/re-pleasing-color-palettes/">visual hierarchy</a>. Too many establish a <a href="https://medium.com/@sn2632/universal-principles-of-design-4b3db103dd32" rel="noopener">cognitive dissonance</a>.</p>
<p>Some planning <a href="https://css-tricks.com/productivity-tip-time-tracking-and-task-lists-unite/">helps productivity</a>. Too much planning <a href="https://basecamp.com/shapeup/3.3-chapter-12#how-to-know-if-the-scopes-are-right" rel="noopener">creates delays</a>.</p>
<hr class="wp-block-separator has-alpha-channel-opacity">
<p>Striking the right balance can be tough. We don’t want cool mama bear’s porridge or hot papa’s bear porridge, but something right in the middle, like baby bear’s porridge.</p>
</description>
<link>https://css-tricks.com/the-law-of-diminishing-returns/</link>
<guid isPermaLink="false">https://css-tricks.com/the-law-of-diminishing-returns/</guid>
<pubDate>Wed, 04 Dec 2024 08:20:24 GMT</pubDate>
<author>Geoff Graham</author>
<enclosure url="https://css-tricks.com/wp-content/uploads/2018/11/cssstacks.png" type="image/jpeg"></enclosure>
<category>inspiration</category>
</item>
<item>
<title>The Different (and Modern) Ways to Toggle Content</title>
<description><blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>If all you have is a hammer, everything looks like a nail.</p>
<cite><a href="https://en.wikipedia.org/wiki/Abraham_Maslow" target="_blank" rel="noreferrer noopener"><em>Abraham Maslow</em></a></cite></blockquote>
<p>It’s easy to default to what you know. When it comes to toggling content, that might be reaching for <code>display: none</code> or <code>opacity: 0</code> with some JavaScript sprinkled in. But the web is more “modern” today, so perhaps now is the right time to get a birds-eye view of the different ways to toggle content — which native APIs are actually supported now, their pros and cons, and some things about them that you might not know (such as any pseudo-elements and other non-obvious stuff).</p>
<!--more-->
<p>So, let’s spend some time looking at <a href="https://css-tricks.com/quick-reminder-that-details-summary-is-the-easiest-way-ever-to-make-an-accordion/">disclosures</a> (<code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code>), the <a href="https://css-tricks.com/how-to-implement-and-style-the-dialog-element/">Dialog API</a>, the <a href="https://css-tricks.com/poppin-in/">Popover API</a>, and more. We’ll look at the right time to use each one depending on your needs. Modal or non-modal? JavaScript or pure HTML/CSS? Not sure? Don’t worry, we’ll go into all that.</p>
<h3 class="wp-block-heading" id="disclosures-details-and-summary-">Disclosures (<code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code>)</h3>
<p><strong>Use case: Accessibly summarizing content while making the content details togglable independently or as an accordion.</strong></p>
<p class="is-style-explanation"><strong>Update 12/12/2024:</strong> A&nbsp;<a href="https://developer.chrome.com/blog/styling-details" rel="noopener">new article on the Chrome blog</a>&nbsp;has demonstrated a couple more interesting ways to use&nbsp;<code>&lt;details&gt;</code>, including <a href="https://codepen.io/web-dot-dev/pen/XWvBZNo" rel="noopener">an animated gallery</a> and <a href="https://codepen.io/web-dot-dev/pen/PoMBQmW" rel="noopener">a partially-open&nbsp;<code>&lt;details&gt;</code></a>&nbsp;(optionally animated using&nbsp;<code>calc-size</code>).</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_yLmoZeo" src="https://codepen.io/anon/embed/preview/yLmoZeo?height=250&amp;theme-id=1&amp;slug-hash=yLmoZeo&amp;default-tab=html,result" height="250" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed yLmoZeo" title="CodePen Embed yLmoZeo" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Going in release order, disclosures — known by their elements as <code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> — marked the first time we were able to toggle content without JavaScript or weird checkbox hacks. But lack of web browser support obviously holds new features back at first, and this one in particular came without keyboard accessibility. So I’d understand if you haven’t used it since it came to Chrome 12 way back in 2011. Out of sight, out of mind, right?</p>
<p>Here’s the low-down:</p>
<ul class="wp-block-list">
<li>It’s functional without JavaScript (without any compromises).</li>
<li>It’s fully stylable without <code>appearance: none</code> or the like.</li>
<li>You can hide the marker without non-standard pseudo-selectors.</li>
<li>You can connect multiple disclosures to create an accordion.</li>
<li><em>Aaaand</em>… it’s fully animatable, as of 2024.</li>
</ul>
<h4 class="wp-block-heading" id="marking-up-disclosures">Marking up disclosures</h4>
<p>What you’re looking for is this:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;details&gt;
&lt;summary&gt;Content summary (always visible)&lt;/summary&gt;
Content (visibility is toggled when summary is clicked on)
&lt;/details&gt;</code></pre>
<p>Behind the scenes, the content’s wrapped in a pseudo-element that as of 2024 we can select using <a href="https://css-tricks.com/almanac/pseudo-selectors/d/details-content/"><code>::details-content</code></a>. To add to this, there’s a <code>::marker</code> pseudo-element that indicates whether the disclosure’s open or closed, which we can customize.</p>
<p>With that in mind, disclosures actually look like this under the hood:</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;details&gt;
&lt;summary&gt;&lt;::marker&gt;&lt;/::marker&gt;Content summary (always visible)&lt;/summary&gt;
&lt;::details-content&gt;
Content (visibility is toggled when summary is clicked on)
&lt;/::details-content&gt;
&lt;/details&gt;</code></pre>
<p>To have the disclosure open by default, give <code>&lt;details&gt;</code> the <code>open</code> attribute, which is what happens behind the scenes when disclosures are opened anyway.</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;details open&gt; ... &lt;/details&gt;</code></pre>
<h4 class="wp-block-heading" id="styling-disclosures">Styling disclosures</h4>
<p>Let’s be real: you probably just want to lose that annoying marker. Well, you can do that by setting the <code>display</code> property of <code>&lt;summary&gt;</code> to anything but <code>list-item</code>:</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">summary {
display: block; /* Or anything else that isn't list-item */
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_OJKxRpd" src="https://codepen.io/anon/embed/preview/OJKxRpd?height=250&amp;theme-id=1&amp;slug-hash=OJKxRpd&amp;default-tab=css,result" height="250" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed OJKxRpd" title="CodePen Embed OJKxRpd" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>Alternatively, you can modify the marker. In fact, the example below utilizes Font Awesome to replace it with another icon, but keep in mind that <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::marker#allowable_properties" rel="noopener"><code>::marker</code> doesn’t support many properties</a>. The most flexible workaround is to wrap the content of <code>&lt;summary&gt;</code> in an element and select it in CSS.</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;details&gt;
&lt;summary&gt;&lt;span&gt;Content summary&lt;/span&gt;&lt;/summary&gt;
Content
&lt;/details&gt;</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">details {
/* The marker */
summary::marker {
content: "\f150";
font-family: "Font Awesome 6 Free";
}
/* The marker when &lt;details&gt; is open */
&amp;[open] summary::marker {
content: "\f151";
}
/* Because ::marker doesn’t support many properties */
summary span {
margin-left: 1ch;
display: inline-block;
}
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_gOVxJer" src="https://codepen.io/anon/embed/preview/gOVxJer?height=250&amp;theme-id=1&amp;slug-hash=gOVxJer&amp;default-tab=css,result" height="250" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed gOVxJer" title="CodePen Embed gOVxJer" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<h4 class="wp-block-heading" id="creating-an-accordion-with-multiple-disclosures">Creating an accordion with multiple disclosures</h4>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_KKrRQXg" src="https://codepen.io/anon/embed/preview/KKrRQXg?height=350&amp;theme-id=1&amp;slug-hash=KKrRQXg&amp;default-tab=html,result" height="350" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed KKrRQXg" title="CodePen Embed KKrRQXg" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p>To create an accordion, name multiple disclosures (they don’t even have to be siblings) with a <code>name</code> attribute and a matching value (similar to how you’d implement <code>&lt;input type="radio"&gt;</code>):</p>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;details name="starWars" open&gt;
&lt;summary&gt;Prequels&lt;/summary&gt;
&lt;ul&gt;
&lt;li&gt;Episode I: The Phantom Menace&lt;/li&gt;
&lt;li&gt;Episode II: Attack of the Clones&lt;/li&gt;
&lt;li&gt;Episode III: Revenge of the Sith&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;details name="starWars"&gt;
&lt;summary&gt;Originals&lt;/summary&gt;
&lt;ul&gt;
&lt;li&gt;Episode IV: A New Hope&lt;/li&gt;
&lt;li&gt;Episode V: The Empire Strikes Back&lt;/li&gt;
&lt;li&gt;Episode VI: Return of the Jedi&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;details name="starWars"&gt;
&lt;summary&gt;Sequels&lt;/summary&gt;
&lt;ul&gt;
&lt;li&gt;Episode VII: The Force Awakens&lt;/li&gt;
&lt;li&gt;Episode VIII: The Last Jedi&lt;/li&gt;
&lt;li&gt;Episode IX: The Rise of Skywalker&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;</code></pre>
<p>Using a wrapper, we can even turn these into horizontal tabs:</p>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_xxvXRxj" src="https://codepen.io/anon/embed/preview/xxvXRxj?height=250&amp;theme-id=1&amp;slug-hash=xxvXRxj&amp;default-tab=result" height="250" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed xxvXRxj" title="CodePen Embed xxvXRxj" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<pre rel="HTML" class="wp-block-csstricks-code-block language-markup" data-line=""><code markup="tt">&lt;div&gt; &lt;!-- Flex wrapper --&gt;
&lt;details name="starWars" open&gt; ... &lt;/details&gt;
&lt;details name="starWars"&gt; ... &lt;/details&gt;
&lt;details name="starWars"&gt; ... &lt;/details&gt;
&lt;/div&gt;</code></pre>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">div {
gap: 1ch;
display: flex;
position: relative;
details {
min-height: 106px; /* Prevents content shift */
&amp;[open] summary,
&amp;[open]::details-content {
background: #eee;
}
&amp;[open]::details-content {
left: 0;
position: absolute;
}
}
}</code></pre>
<p>…or, using 2024’s <a href="https://css-tricks.com/css-anchor-positioning-guide/">Anchor Positioning API</a>, <em>vertical</em> tabs (same HTML):</p>
<pre rel="CSS" class="wp-block-csstricks-code-block language-css" data-line=""><code markup="tt">div {
display: inline-grid;
anchor-name: --wrapper;
details[open] {
summary,
&amp;::details-content {
background: #eee;
}
&amp;::details-content {
position: absolute;
position-anchor: --wrapper;
top: anchor(top);
left: anchor(right);
}
}
}</code></pre>
<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_eYqGrOm" src="https://codepen.io/anon/embed/eYqGrOm?height=350&amp;theme-id=1&amp;slug-hash=eYqGrOm&amp;default-tab=css,result" height="350" scrolling="no" frameborder="0" allowfullscreen="" allowpaymentrequest="" name="CodePen Embed eYqGrOm" title="CodePen Embed eYqGrOm" class="cp_embed_iframe" style="width:100%;overflow:hidden" referrerpolicy="no-referrer">CodePen Embed Fallback</iframe></div>
<p class="is-style-explanation">If you’re looking for some wild ideas on what we can do with the Popover API in CSS, check out <a href="https://css-tricks.com/popover-the-balloons/">John Rhea’s article</a> in which he makes an interactive game solely out of disclosures!</p>
<h4 class="wp-block-heading" id="adding-javascript-functionality">Adding JavaScript functionality</h4>
<p>Want to add some JavaScript functionality?</p>
<pre rel="JavaScript" class="wp-block-csstricks-code-block language-javascript" data-line=""><code markup="tt">// Optional: select and loop multiple disclosures
document.querySelectorAll("details").forEach(details =&gt; {
details.addEventListener("toggle", () =&gt; {
// The disclosure was toggled
if (details.open) {
// The disclosure was opened
} else {
// The disclosure was closed
}
});
});</code></pre>
<h4 class="wp-block-heading" id="creating-accessible-disclosures">Creating accessible disclosures</h4>
<p>Disclosures are accessible as long as you follow a few rules. For example, <code>&lt;summary&gt;</code> is basically a <code> |
Involved Issue / 该 PR 相关 Issue
Close #
Example for the Proposed Route(s) / 路由地址示例
New RSS Route Checklist / 新 RSS 路由检查表
Puppeteer
Note / 说明