{"id":6948,"date":"2025-09-19T18:05:13","date_gmt":"2025-09-19T23:05:13","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=6948"},"modified":"2025-11-08T13:43:37","modified_gmt":"2025-11-08T18:43:37","slug":"what-you-need-to-know-about-modern-css-2025-edition","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-2025-edition\/","title":{"rendered":"What You Need to Know about Modern CSS (2025 Edition)"},"content":{"rendered":"\n<p class=\"has-text-align-left\">We published an edition of <a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/\">What You Need To Know about Modern CSS last year (2024)<\/a>, and for a while I really wasn&#8217;t sure if only a year later we&#8217;d have enough stuff to warrant and new yearly version. But time, and CSS, have rolled forward, and guess what? There is <em>more<\/em> this year than there was last. At least in this somewhat arbitrary list of <em>&#8220;things Chris thinks are valuable to know that are either pretty fresh or have enjoyed a boost in browser support.&#8221;<\/em><\/p>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">Animate to Auto<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>We don&#8217;t often set the <code>height<\/code> of elements that contain arbitrary content. We usually let elements like that be as tall as they need to be for the content. The trouble with that is we haven&#8217;t been able to animate from a fixed number (like zero) to whatever that intrinsic height is (or vice versa). In other words, animate to <code>auto<\/code> (or other sizing keywords like <code>min-content<\/code> and the like). <\/p>\n\n\n\n<p>Now, we can opt-in to being able to animate to these keywords, like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">interpolate-size<\/span>: allow-keywords;\n  <span class=\"hljs-comment\">\/* Now if we transition \n     \"height: 0;\" to \"height: auto;\" \n     anywhere, it will work *\/<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If we don&#8217;t want to use an opt-in like that, alternatively, we can use the <code>calc-size()<\/code> function to make the transition work without needing <code>interpolate-size<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.content<\/span> {\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">3<\/span>lh;\n  <span class=\"hljs-attribute\">overflow<\/span>: hidden;\n  <span class=\"hljs-attribute\">transition<\/span>: height <span class=\"hljs-number\">0.2s<\/span>;\n  \n  &amp;.expanded {\n    <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-built_in\">calc-size<\/span>(auto, size);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>This is the first time we&#8217;ve ever been able to do this in CSS. It&#8217;s a relatively common need and it&#8217;s wonderful to be able to do it so naturally, without breaking behavior. <\/p>\n\n\n\n<p>And it&#8217;s not just <code>height<\/code> (it could be any property that takes a size) and it&#8217;s not just <code>auto<\/code> (it could be any sizing keyword).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Just Chrome.<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Yes! Typically, this kind of animation isn&#8217;t a hard requirement, just a nice-to-have.<\/td><\/tr><tr><td>Polyfill<\/td><td>Not really. The old fallbacks including things like animating <code>max-height<\/code> to a beyond-what-is-needed value, or using JavaScript to attempt to measure the size off-screen and then doing the real animation to that number. Both suck.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_01992602-6209-7ff6-9aec-9157440104cc\" src=\"\/\/codepen.io\/editor\/anon\/embed\/01992602-6209-7ff6-9aec-9157440104cc?height=1300&amp;theme-id=1&amp;slug-hash=01992602-6209-7ff6-9aec-9157440104cc&amp;default-tab=css,result\" height=\"1300\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 01992602-6209-7ff6-9aec-9157440104cc\" title=\"CodePen Embed 01992602-6209-7ff6-9aec-9157440104cc\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">Popovers &amp; Invokers<\/h2>\n\n\n\n<p>These are separate and independently useful things, and really rather HTML-focused, but it&#8217;s nice to show them off together as they complement each other nicely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>A <code>popover<\/code> is an attribute you can put on any HTML element that essentially gives it open\/close functionality. It will then have JavaScript APIs for opening and closing it. It&#8217;s <a href=\"https:\/\/frontendmasters.com\/blog\/whats-the-difference-between-htmls-dialog-element-and-popovers\/\">similar-but-different to modals<\/a>. Think of them more in the tooltip category, or something that you might want more than one of open sometimes. <\/p>\n\n\n\n<p>Invokes are also HTML attributes that give us access to those JavaScript APIs in a declarative markup way.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>Implementing functionality at the HTML level is very powerful. It will work without JavaScript, be done in an accessible way, and likely get important UX features right that you might miss when implementing yourself.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Popovers are everywhere, but invokers are Chrome only at time of publication. <br><br>There are sub-features here though, like <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Popover_API\/Using#using_hint_popover_state\">popover=\"hint\"<\/a><\/code> which has <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Reference\/Global_attributes\/popover#browser_compatibility\">slightly less support<\/a> so far. <\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Not so much. These type of functions typically need to <em>work<\/em>, so ensuring they do with a polyfill instead of handling multiple behaviors is best.<\/td><\/tr><tr><td>Polyfill<\/td><td>Yep! For both:<br><br><a href=\"https:\/\/github.com\/oddbird\/popover-polyfill\">Popovers Polyfill<br><\/a><a href=\"https:\/\/github.com\/keithamus\/invokers-polyfill\">Invokers Polyfill<\/a><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<p>Remember there are JavaScript APIs for popovers also, like <code>myPopover.showPopover()<\/code> and <code>secondPopover.hidePopover()<\/code> but what I&#8217;m showing off here is specifically the HTML invoker controls for them. There are <em>also<\/em> some alternative HTML controls (e.g. <code>popovertarget=\"mypopover\" popovertargetaction=\"show\"<\/code>) which I suppose are fine to use as well? But something feels better to me about the more generic command invokers approach.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019948c7-09d1-7f29-b676-2b57fdec4f8f\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019948c7-09d1-7f29-b676-2b57fdec4f8f?height=450&amp;theme-id=1&amp;slug-hash=019948c7-09d1-7f29-b676-2b57fdec4f8f&amp;default-tab=html,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019948c7-09d1-7f29-b676-2b57fdec4f8f\" title=\"CodePen Embed 019948c7-09d1-7f29-b676-2b57fdec4f8f\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p><em>Also<\/em> \u2014 remember popovers pair particularly well with anchor positioning which is another CSS modern miracle.<\/p>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">@function<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>CSS has lots of functions already. Think of <code>calc()<\/code>, <code>attr()<\/code>, <code>clamp()<\/code>, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_Values_and_Units\/CSS_Value_Functions\">perhaps hundreds<\/a> more. They are actually technically called CSS <em>value<\/em> functions as they always return a single value. <\/p>\n\n\n\n<p>The magic with with <code>@function<\/code> is that now <em>you can write your own.<\/em><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@function<\/span> --titleBuilder(--name) {\n  <span class=\"hljs-selector-tag\">result<\/span>: <span class=\"hljs-selector-tag\">var<\/span>(<span class=\"hljs-selector-tag\">--name<\/span>) \" <span class=\"hljs-selector-tag\">is<\/span> <span class=\"hljs-selector-tag\">cool<\/span>.\";\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>Abstracting logic into functions is a computer programming concept as old as computers itself. It can just <em>feel right<\/em>, not to mention be DRY, to put code and logic into a single shared place rather than repeat yourself or complicate the more declarative areas of your CSS with complex statements.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome only<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>It depends on what you&#8217;re trying to use the value for. If it&#8217;s reasonable, it may be as simple as:<br><br><code>property: fallback;<br>property: --function();<\/code><\/td><\/tr><tr><td>Polyfill<\/td><td>Not really. Sass has functions but are not based on the same spec and will not work the same.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019930ad-8e97-7b37-9330-e5cae3d2c938\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019930ad-8e97-7b37-9330-e5cae3d2c938?height=450&amp;theme-id=1&amp;slug-hash=019930ad-8e97-7b37-9330-e5cae3d2c938&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019930ad-8e97-7b37-9330-e5cae3d2c938\" title=\"CodePen Embed 019930ad-8e97-7b37-9330-e5cae3d2c938\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Other Resources<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Una Kravets: <a href=\"https:\/\/una.im\/5-css-functions\/\">5 Useful CSS functions using the new @function rule<\/a><\/li>\n\n\n\n<li>Bramus Van Damme: <a href=\"https:\/\/www.bram.us\/2025\/02\/18\/css-at-function-and-css-if\/\">CSS&nbsp;<code>@function<\/code>&nbsp;+ CSS&nbsp;<code>if()<\/code>&nbsp;= \ud83e\udd2f<\/a><\/li>\n\n\n\n<li>Juan Diego Rodr\u00edguez: <a href=\"https:\/\/css-tricks.com\/functions-in-css\/\">Functions in CSS?!<\/a><\/li>\n\n\n\n<li>Draft: <a href=\"https:\/\/www.w3.org\/TR\/css-mixins-1\/\">CSS Functions and Mixins Module<\/a><\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">if()<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>Conceptually, CSS is already full of conditional logic. Selectors themselves will match and apply styles <em>if<\/em> they match an HTML element. Or media queries will apply <em>if<\/em> their conditions are met. <\/p>\n\n\n\n<p>But <a href=\"https:\/\/developer.chrome.com\/blog\/if-article\">the <code>if()<\/code> function<\/a>, surprisingly, is the first specific logical construct that exists soley for the function of applying logical branches.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>Like all functions, including custom @functions like above, <code>if()<\/code> returns a single value. It just has a syntax that might help make for more readable code and potentially prevent certain types of code repetition. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome only<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>It depends on the property\/value you are using it with. If you&#8217;re OK with a fallback value, it might be fine to use.<br><br><code>property: fallback;<br>property: if(<br>  style(--x: true): value;<br>  else: fallback;<br>);<\/code><\/td><\/tr><tr><td>Polyfill<\/td><td>Not really. CSS processes tend to have logical constructs like this, but they will not re-evaluate based on dynamic values and DOM placement and such.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<p>Baking logic into a single value like this is pretty neat!<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.grid<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: grid;\n  <span class=\"hljs-attribute\">grid-template-columns<\/span>:\n    <span class=\"hljs-built_in\">if<\/span>(\n       media(width &gt; <span class=\"hljs-number\">900px<\/span>): <span class=\"hljs-built_in\">repeat<\/span>(auto-fit, minmax(<span class=\"hljs-number\">200px<\/span>, <span class=\"hljs-number\">1<\/span>fr));\n       media(width &gt; 600px): repeat(3, 1fr);\n       media(width &gt; 300px): repeat(2, 1fr);\n       <span class=\"hljs-attribute\">else<\/span>: <span class=\"hljs-number\">1<\/span>fr;\n    ); \n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The syntax is a lot like a switch statement with as many conditions as you need. The first match wins.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">if<\/span>(\n  <span class=\"hljs-selector-tag\">condition<\/span>: <span class=\"hljs-selector-tag\">value<\/span>;\n  <span class=\"hljs-selector-tag\">condition<\/span>: <span class=\"hljs-selector-tag\">value<\/span>;\n  <span class=\"hljs-selector-tag\">else<\/span>: <span class=\"hljs-selector-tag\">value<\/span>;\n)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Conditions can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>media()<\/code><\/li>\n\n\n\n<li><code>supports()<\/code><\/li>\n\n\n\n<li><code>style()<\/code><\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">field-sizing<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>The new <code>field-sizing<\/code> property in CSS is for creating form fields (or any editable element) that automatically grows to to the size of their contents. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>This is a need that developers have been creating in JavaScript since forever. The most classic example is the <code>&lt;textarea&gt;<\/code>, which makes a lot of sense to be sized to as large as the user entering information into it needs to be, without having to explicitly resize it (which is difficult at best on a small mobile screen). But inline resizing <a href=\"https:\/\/bsky.app\/profile\/eva.town\/post\/3lynv7jniys2u\">can be nice too<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome and looks to be coming soon to Safari.<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Yes! This isn&#8217;t a hard requirement usually but more of a UX nicety. <\/td><\/tr><tr><td>Polyfill<\/td><td>There is some <a href=\"https:\/\/chriscoyier.net\/2023\/09\/29\/css-solves-auto-expanding-textareas-probably-eventually\/\">very lightweight JavaScript<\/a> to replicate this if you want to.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_01993ac3-0511-7ca2-b400-43dac665e755\" src=\"\/\/codepen.io\/editor\/anon\/embed\/01993ac3-0511-7ca2-b400-43dac665e755?height=450&amp;theme-id=1&amp;slug-hash=01993ac3-0511-7ca2-b400-43dac665e755&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 01993ac3-0511-7ca2-b400-43dac665e755\" title=\"CodePen Embed 01993ac3-0511-7ca2-b400-43dac665e755\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">Custom Selects<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>Styling the <em>outside<\/em> of a <code>&lt;select&gt;<\/code> has been decently possible for a while, but when you open it up, what the browser renders is an operating-system specific default. Now you can opt-in to entirely styleable select menus.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome only<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>100%. It just falls back to a not-styled <code>&lt;select&gt;<\/code> which is fine.<\/td><\/tr><tr><td>Polyfill<\/td><td>Back when this endeavor was using <code>&lt;selectlist&gt;<\/code> <a href=\"https:\/\/github.com\/luwes\/selectlist-polyfill\">there was<\/a>, but in my opinion the progressive enhancement story is so good you don&#8217;t need it. <\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<p><a href=\"https:\/\/developer.chrome.com\/blog\/rfc-customizable-select\">First you opt-in<\/a> then you <a href=\"https:\/\/frontendmasters.com\/blog\/custom-select-that-comes-up-from-the-bottom-on-mobile\/\">go nuts<\/a>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">select<\/span>,\n<span class=\"hljs-selector-pseudo\">::picker(select)<\/span> {\n  <span class=\"hljs-attribute\">appearance<\/span>: base-select;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_eYojgZw\" src=\"\/\/codepen.io\/anon\/embed\/eYojgZw?height=450&amp;theme-id=1&amp;slug-hash=eYojgZw&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed eYojgZw\" title=\"CodePen Embed eYojgZw\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">text-wrap<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>The <code>text-wrap<\/code> property in CSS allows you to instruct the browser that it can and should wrap text a bit differently. For example, <code>text-wrap: balance;<\/code> will attempt to have each line of text as close to the same length as possible. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>This can be a much nicer default for large <code>font-size<\/code> elements like headers. It also can help with single-word-on-the-next-line orphans, but there is also <code>text-wrap: pretty;<\/code> which can do that, and <a href=\"https:\/\/webkit.org\/blog\/16547\/better-typography-with-text-wrap-pretty\/\">is designed<\/a> for smaller-longer text as well, creating better-reading text. Essentially: better typography for free.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td><code>balance<\/code> is supported across the board but <code>pretty<\/code> is only Chrome and Safari so far.<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Absolutely. As important as we might agree typography is, without these enhancements the text is still readable and accessible.<\/td><\/tr><tr><td>Polyfill<\/td><td><a href=\"https:\/\/arc.net\/l\/quote\/ulftlzvc\">There is one for balance<\/a>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_01996388-9b45-7cdc-9c2e-089f052527c4\" src=\"\/\/codepen.io\/editor\/anon\/embed\/01996388-9b45-7cdc-9c2e-089f052527c4?height=650&amp;theme-id=1&amp;slug-hash=01996388-9b45-7cdc-9c2e-089f052527c4&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 01996388-9b45-7cdc-9c2e-089f052527c4\" title=\"CodePen Embed 01996388-9b45-7cdc-9c2e-089f052527c4\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Resources<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Jen Simmons: <a href=\"https:\/\/webkit.org\/blog\/16547\/better-typography-with-text-wrap-pretty\/\">Better typography with text-wrap pretty<\/a><\/li>\n\n\n\n<li>Stephanie Stimac: <a href=\"https:\/\/blog.stephaniestimac.com\/posts\/2023\/10\/css-text-wrap\/\">When to use CSS text-wrap: balance; vs text-wrap: pretty;<\/a><\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">linear() easing<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>I think this one a <em>little<\/em> confusing because <code>linear<\/code> as a keyword for <code>transition-timing-function<\/code> or <code>animation-timing-function<\/code> kinda means &#8220;flat and boring&#8221; (which is sometimes what you want, like when changing opacity for istance). But this <a href=\"https:\/\/developer.chrome.com\/docs\/css-ui\/css-linear-easing-function#a_tool_to_help\"><code>linear()<\/code> function<\/a> <em>actually<\/em> means you&#8217;re about to do an easing approach that is probably extra fancy, like having a &#8220;bouncing&#8221; effect.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>Even the fancy <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/easing-function\/cubic-bezier\">cubic-bezier()<\/a><\/code> function can only do a really limited bouncing affect with an animation timing, but the sky is the limit with <code>linear()<\/code> because it takes an unlimited number of points. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Across the board<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Sure! You could fall back to a named easing value or a <code>cubic-bezier()<\/code><\/td><\/tr><tr><td>Polyfill<\/td><td>Not that I know of, but if fancy easing is very important to you, JavaScript libraries <a href=\"https:\/\/gsap.com\/docs\/v3\/Eases\/\">like GSAP<\/a> have this covered in a way that will work in all browsers. <\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.bounce<\/span> {\n  <span class=\"hljs-attribute\">animation-timing-function<\/span>: <span class=\"hljs-built_in\">linear<\/span>(\n    <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0.004<\/span>, <span class=\"hljs-number\">0.016<\/span>, <span class=\"hljs-number\">0.035<\/span>, <span class=\"hljs-number\">0.063<\/span>, <span class=\"hljs-number\">0.098<\/span>, <span class=\"hljs-number\">0.141<\/span> <span class=\"hljs-number\">13.6%<\/span>, <span class=\"hljs-number\">0.25<\/span>, <span class=\"hljs-number\">0.391<\/span>, <span class=\"hljs-number\">0.563<\/span>, <span class=\"hljs-number\">0.765<\/span>,\n    <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">0.891<\/span> <span class=\"hljs-number\">40.9%<\/span>, <span class=\"hljs-number\">0.848<\/span>, <span class=\"hljs-number\">0.813<\/span>, <span class=\"hljs-number\">0.785<\/span>, <span class=\"hljs-number\">0.766<\/span>, <span class=\"hljs-number\">0.754<\/span>, <span class=\"hljs-number\">0.75<\/span>, <span class=\"hljs-number\">0.754<\/span>, <span class=\"hljs-number\">0.766<\/span>, <span class=\"hljs-number\">0.785<\/span>,\n    <span class=\"hljs-number\">0.813<\/span>, <span class=\"hljs-number\">0.848<\/span>, <span class=\"hljs-number\">0.891<\/span> <span class=\"hljs-number\">68.2%<\/span>, <span class=\"hljs-number\">1<\/span> <span class=\"hljs-number\">72.7%<\/span>, <span class=\"hljs-number\">0.973<\/span>, <span class=\"hljs-number\">0.953<\/span>, <span class=\"hljs-number\">0.941<\/span>, <span class=\"hljs-number\">0.938<\/span>, <span class=\"hljs-number\">0.941<\/span>, <span class=\"hljs-number\">0.953<\/span>,\n    <span class=\"hljs-number\">0.973<\/span>, <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">0.988<\/span>, <span class=\"hljs-number\">0.984<\/span>, <span class=\"hljs-number\">0.988<\/span>, <span class=\"hljs-number\">1<\/span>\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_01993fdd-5fd1-751d-bf26-f43dd3140396\" src=\"\/\/codepen.io\/editor\/anon\/embed\/01993fdd-5fd1-751d-bf26-f43dd3140396?height=450&amp;theme-id=1&amp;slug-hash=01993fdd-5fd1-751d-bf26-f43dd3140396&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 01993fdd-5fd1-751d-bf26-f43dd3140396\" title=\"CodePen Embed 01993fdd-5fd1-751d-bf26-f43dd3140396\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Resources<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Jake Archibald: <a href=\"https:\/\/linear-easing-generator.netlify.app\/\">linear() easing generator<\/a><\/li>\n\n\n\n<li>Matthias Martin: <a href=\"https:\/\/easingwizard.com\/\">Easing Wizard<\/a><\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">shape()<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>While CSS has had a <code>path()<\/code> function for a while, it only took a 1-for-1 copy of the <code>d<\/code> attribute from SVG&#8217;s <code>&lt;path&gt;<\/code> element, which was forced to work only in pixels and has a <a href=\"https:\/\/css-tricks.com\/svg-path-syntax-illustrated-guide\/\">somewhat obtuse syntax<\/a>. The <a href=\"https:\/\/drafts.csswg.org\/css-shapes-2\/#shape-function\"><code>shape()<\/code> function<\/a> is basically that, but fixed up properly for CSS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>The <code>shape()<\/code> function can essentially draw anything. You can apply it as a value to <code>clip-path<\/code>, cutting elements into any shape, and do so responsively and with all the power of CSS (meaning all the units, custom properties, media queries, etc). You can also apply it to <code>offset-path()<\/code> meaning placement and animation along any drawable path. And presumably soon <code>shape-outside<\/code> as well.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>It&#8217;s in Chrome and Safari and flagged in Firefox, so everywhere fairly soon.<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Probably! Cutting stuff out and moving stuff along paths is usually the stuff of aesthetics and fun and falling back to less fancy options is acceptable.<\/td><\/tr><tr><td>Polyfill<\/td><td>Not really. You&#8217;re better off working on a good fallback.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<p><a href=\"https:\/\/path-to-shape.netlify.app\/\">Literally any SVG path<\/a> can be converted to <code>shape()<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.arrow<\/span> {\n  <span class=\"hljs-attribute\">clip-path<\/span>: <span class=\"hljs-built_in\">shape<\/span>(\n    evenodd from <span class=\"hljs-number\">97.788201%<\/span> <span class=\"hljs-number\">41.50201%<\/span>, \n    line by -<span class=\"hljs-number\">30.839077%<\/span> -<span class=\"hljs-number\">41.50201%<\/span>, \n    curve by -<span class=\"hljs-number\">10.419412%<\/span> <span class=\"hljs-number\">0%<\/span> with -<span class=\"hljs-number\">2.841275%<\/span> -<span class=\"hljs-number\">3.823154%<\/span> \/ -<span class=\"hljs-number\">7.578137%<\/span> -<span class=\"hljs-number\">3.823154%<\/span>, \n    smooth by <span class=\"hljs-number\">0%<\/span> <span class=\"hljs-number\">14.020119%<\/span> with -<span class=\"hljs-number\">2.841275%<\/span> <span class=\"hljs-number\">10.196965%<\/span>, \n    line by <span class=\"hljs-number\">18.207445%<\/span> <span class=\"hljs-number\">24.648236%<\/span>, hline by -<span class=\"hljs-number\">67.368705%<\/span>, \n    curve by -<span class=\"hljs-number\">7.368452%<\/span> <span class=\"hljs-number\">9.914818%<\/span> with -<span class=\"hljs-number\">4.103596%<\/span> <span class=\"hljs-number\">0%<\/span> \/ -<span class=\"hljs-number\">7.368452%<\/span> <span class=\"hljs-number\">4.393114%<\/span>, \n    smooth by <span class=\"hljs-number\">7.368452%<\/span> <span class=\"hljs-number\">9.914818%<\/span> with <span class=\"hljs-number\">3.264856%<\/span> <span class=\"hljs-number\">9.914818%<\/span>, \n    hline by <span class=\"hljs-number\">67.368705%<\/span>, line by -<span class=\"hljs-number\">18.211656%<\/span> <span class=\"hljs-number\">24.50518%<\/span>, \n    curve by <span class=\"hljs-number\">0%<\/span> <span class=\"hljs-number\">14.020119%<\/span> with -<span class=\"hljs-number\">2.841275%<\/span> <span class=\"hljs-number\">3.823154%<\/span> \/ -<span class=\"hljs-number\">2.841275%<\/span> <span class=\"hljs-number\">10.196965%<\/span>, \n    curve by <span class=\"hljs-number\">5.26318%<\/span> <span class=\"hljs-number\">2.976712%<\/span> with <span class=\"hljs-number\">1.472006%<\/span> <span class=\"hljs-number\">1.980697%<\/span> \/ <span class=\"hljs-number\">3.367593%<\/span> <span class=\"hljs-number\">2.976712%<\/span>, \n    smooth by <span class=\"hljs-number\">5.26318%<\/span> -<span class=\"hljs-number\">2.976712%<\/span> with <span class=\"hljs-number\">3.791174%<\/span> -<span class=\"hljs-number\">0.990377%<\/span>, line by <span class=\"hljs-number\">30.735919%<\/span> -<span class=\"hljs-number\">41.357537%<\/span>, \n    curve by <span class=\"hljs-number\">2.21222%<\/span> -<span class=\"hljs-number\">7.082013%<\/span> with <span class=\"hljs-number\">1.369269%<\/span> -<span class=\"hljs-number\">1.842456%<\/span> \/ <span class=\"hljs-number\">2.21222%<\/span> -<span class=\"hljs-number\">4.393114%<\/span>, \n    smooth by -<span class=\"hljs-number\">2.21222%<\/span> -<span class=\"hljs-number\">7.082013%<\/span> with -<span class=\"hljs-number\">0.736024%<\/span> -<span class=\"hljs-number\">5.239556%<\/span>, \n    close\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The natural re-sizeability and more readable syntax is big advantage over <code>path()<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_0199597b-d364-76f2-a843-0e434ebaaac8\" src=\"\/\/codepen.io\/editor\/anon\/embed\/0199597b-d364-76f2-a843-0e434ebaaac8?height=450&amp;theme-id=1&amp;slug-hash=0199597b-d364-76f2-a843-0e434ebaaac8&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 0199597b-d364-76f2-a843-0e434ebaaac8\" title=\"CodePen Embed 0199597b-d364-76f2-a843-0e434ebaaac8\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">More Powerful attr()<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>The <code>attr()<\/code> function in CSS can pull the string value of the matching HTML element. So with <code>&lt;div data-name=\"Chris\"&gt;<\/code> I can do <code>div::before { content: attr(data-name); }<\/code> to pull off an use &#8220;Chris&#8221; as a string. But now, you can apply <em>types<\/em> to the values you pull, making it a lot more useful.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>Things like numbers and colors are a lot more useful to pluck off and use from HTML attributes than strings are. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">attr(data-count type(<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">number<\/span>&gt;<\/span>))<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome only<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>It depends on what you&#8217;re doing with the values. If you&#8217;re passing through a color for a little aesthetic flourish, sure, it can be a enhancement that fallback to something else or nothing. If it&#8217;s crucial layout information, probably not.<\/td><\/tr><tr><td>Polyfill<\/td><td>Not that I know of. <\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_0199599c-caf7-7245-b445-bde7a0d43fe9\" src=\"\/\/codepen.io\/editor\/anon\/embed\/0199599c-caf7-7245-b445-bde7a0d43fe9?height=1000&amp;theme-id=1&amp;slug-hash=0199599c-caf7-7245-b445-bde7a0d43fe9&amp;default-tab=result\" height=\"1000\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 0199599c-caf7-7245-b445-bde7a0d43fe9\" title=\"CodePen Embed 0199599c-caf7-7245-b445-bde7a0d43fe9\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-group feature-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">Reading Flow<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What is this?<\/h3>\n\n\n\n<p>There are various ways to change the layout such that the visual order no longer matches the source order. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/reading-flow\">The new <code>reading-order<\/code> property<\/a> allow us to continue to do that while updating the behavior such that tabbing through the elements happens in a predictable manner.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why should I care?<\/h3>\n\n\n\n<p>For a long time we&#8217;ve been told: don&#8217;t re-order layout! The source order should match the visual order as closely as possible, so that tabbing focus through a page happens in a sensible order. When you mess with the visual order and not source order, tabbing can become zig-zaggy and unpredictable, even causing scrolling, which is a bad experience and a hit to accessibility. Now we can inform the browser that we&#8217;ve made changes and to follow a tabbing order that makes sense for the layout style we&#8217;re using.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Support<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td>Browser Support<\/td><td>Chrome only<\/td><\/tr><tr><td>Progressive Enhancement<\/td><td>Not particularly. We should probably not be re-ordering layout wildly until this feature is more safely across all browsers. <\/td><\/tr><tr><td>Polyfill<\/td><td>No, but if you were so-inclined you could (hopefully very intelligently) update the <code>tabindex<\/code> property of the elements to a sensible order.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Usage Example<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.grid<\/span> {\n  <span class=\"hljs-attribute\">reading-flow<\/span>: grid-rows;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Re-ordering a grid layout is perhaps of the most common things to re-order, and having the tabbing order follow the rows after re-arranging is sensible, so that&#8217;s what the above line of code is doing. But you&#8217;ll need to set the value to match what you are doing. For instance if you are using flexbox layout, you&#8217;d likely set the value to <code>flex-flow<\/code>. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/reading-flow#value\">See MDN for the list of values<\/a>. <\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_jEEdewP\" src=\"\/\/codepen.io\/anon\/embed\/jEEdewP?height=450&amp;theme-id=1&amp;slug-hash=jEEdewP&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed jEEdewP\" title=\"CodePen Embed jEEdewP\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Resources<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Rachel Andrew: <a href=\"https:\/\/rachelandrew.co.uk\/archives\/2025\/05\/02\/reading-flow-ships-in-chrome-137\/\">Reading flow ships in Chrome 137<\/a><\/li>\n\n\n\n<li>Daniel Schwarz: <a href=\"https:\/\/css-tricks.com\/what-we-know-so-far-about-css-reading-order\/\">What We Know (So Far) About CSS Reading&nbsp;Order<\/a><\/li>\n\n\n\n<li>Di Zhang: <a href=\"https:\/\/developer.chrome.com\/blog\/reading-flow\">Use CSS reading-flow for logical sequential focus navigation<\/a><\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Stuff to Keep an Eye On<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&#8220;Masonry&#8221; layout, despite having different preliminary implementations, is not yet finalized, but there is enough movement on it it feels like we&#8217;ll see that get sorted out next year. The most interesting development at the moment is <a href=\"https:\/\/webkit.org\/blog\/17219\/item-flow-part-2-next-steps-for-masonry\/\">the proposal of <code>item-flow<\/code><\/a> and how that could not only help with Masonry but bring other layout possibilities to other layout mechanisms beyond grid.<\/li>\n\n\n\n<li>The CSS function <code>random()<\/code> is in Safari <a href=\"https:\/\/frontendmasters.com\/blog\/very-early-playing-with-random-in-css\/\">and it&#8217;s amazing<\/a>. <\/li>\n\n\n\n<li>The CSS property <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/margin-trim\">margin-trim<\/a><\/code> is super useful and we&#8217;re waiting patiently to be able to use it more than just Safari. <\/li>\n\n\n\n<li>The <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/sibling-index\">sibling-index()<\/a><\/code> and <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/sibling-count\">sibling-count()<\/a><\/code> functions are in Chrome and, for one thing, are really useful for staggered animations. <\/li>\n\n\n\n<li>For View Transitions, <code>view-transition-name: match-element;<\/code> is awfully handy as it prevents us from needing to generate unique names on absolutely everything. Also \u2014 Firefox has View Transitions in development, so that&#8217;s huge.<\/li>\n\n\n\n<li>We should be able to use <code>calc()<\/code> to multiply and divide with units (instead of requiring the 2nd to be unitless) <a href=\"https:\/\/wpt.fyi\/results\/css\/css-values\/getComputedStyle-calc-mixed-units-003.html?label=experimental&amp;label=master&amp;aligned\">soon<\/a>, instead of needing a <a href=\"https:\/\/dev.to\/janeori\/css-type-casting-to-numeric-tanatan2-scalars-582j\">hack<\/a>.<\/li>\n\n\n\n<li>We never did get &#8220;<a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/4770\">CSS4<\/a>&#8221; (<a href=\"https:\/\/www.youtube.com\/watch?v=j4mOm1qic7k\">Zoran explains nicely<\/a>) but I for one still think some kind of named versioning system would be of benefit to <em>everyone<\/em>.<\/li>\n\n\n\n<li>If you&#8217;re interested in a more straightforward list of &#8220;new CSS things&#8221; for say the last ~5 years, <a href=\"https:\/\/nerdy.dev\/cascading-secret-sauce\">Adam Argyle has a great list<\/a>. <\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Great Stuff to Remember<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/#container-queries-size\">Container queries<\/a> (and units) are still relatively new and the best thing since media queries in CSS. <\/li>\n\n\n\n<li>The <a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/#the-has-pseudo-selector\"><code>:has()<\/code> pseudo-class<\/a> is wildly useful for selecting elements where the children exist or are in a particular state.<\/li>\n\n\n\n<li>Ultra cool modern CSS features like <a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/#view-transitions\">View Transitions<\/a>, <a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/#anchor-positioning\">Anchor Positioning<\/a>, and <a href=\"https:\/\/frontendmasters.com\/blog\/what-you-need-to-know-about-modern-css-spring-2024-edition\/#scroll-driven-animations\">Scroll-Driven Animations<\/a> have all made it to Safari.<\/li>\n\n\n\n<li>All the useful extra viewport units (shoutout <code>dvh<\/code>) <a href=\"https:\/\/web.dev\/blog\/viewport-units\">are now in baseline<\/a>.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>If you thought 2024 was packed with amazing new CSS, well, you&#8217;re right. But so is 2025 and it keeps looking bright. Check out our list of the best stuff with easy-to-reference examples.<\/p>\n","protected":false},"author":1,"featured_media":7203,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[395,300,400,7,401,396,399,35,260,388,403,38],"class_list":["post-6948","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-function","tag-attr","tag-calc-size","tag-css","tag-field-sizing","tag-if","tag-interpolate-size","tag-invokers","tag-linear","tag-random","tag-reading-flow","tag-text-wrap"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/09\/thumb.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6948","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=6948"}],"version-history":[{"count":55,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6948\/revisions"}],"predecessor-version":[{"id":7731,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6948\/revisions\/7731"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/7203"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=6948"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=6948"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=6948"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}