https://frontendmasters.com/blog/what-you-need-to-know-about-modern-css-spring-2024-edition/ Search Frontend Masters -- Boost Courses Learn Become a Member - Back to FrontendMasters.com What You Need to Know about Modern CSS (Spring 2024 Edition) March 26, 2024 My goal with this bookmarkable guide is to provide a list of (frankly: incredible) new additions to CSS lately. There is no hardline criteria for this list other than that these things are all fairly new and my sense is that many people aren't aware of these things. Or even if they are, they don't have a great understanding of them and could use a plain language explanation of what it is, why they should care, and a bit of reference code. Maybe that's you. I'd like to work on our collective muscle memory on these features. Like I said, "even if you know about this stuff, it takes time to build the muscle memory around it." There is quite a bit more syntax, detail, and nuance to these things than I am presenting here. I want you to know what's possible, reference the most basic usage and syntax, then dig deeper when you need to. Container Queries (Size) What are Size Container Queries? Container Queries allow you to write styles that apply to the children of a container element when that container matches certain media conditions, typically a width measurement.
Code language: HTML, XML (xml) .element-wrap { container: element / inline-size; } @container element (min-inline-size: 300px) { .element { display: flex; gap: 1rem; } }Code language: CSS (css) When should you care? If you've ever thought: I wish I could make styling decisions based on the size of this element, not the entire page like @media queries force me to do. Then using @container queries are for you! People who work on design systems or heavily component-based websites will probably mostly use Container Queries to style things based on size, because the size of the entire page is a poor proxy for the size of a component. Support Browser Support Full Progressive Potentially -- if it's not critical what you are Enhancement? styling, then yes. Polyfillable Yes Basic Demo of Usage Use the resizer in the middle to see the calendar change layout depending on how much space it has. It has three breakpoints of its own. CodePen Embed Fallback Container Queries (Style) What are Style Container Queries? Container Style Queries allow you to apply styles when a given Custom Property has a given value. .container { --variant: 1; &.variant2 { --variant: 2; } } @container style(--variant: 1) { button { } /* You can't style .container, but can select inside it */ .other-things { } } @container style(--variant: 2) { button { } .whatever { } }Code language: CSS (css) When should you care? Have you ever wanted a mixin in CSS? As in, you set one property but get multiple properties. Sass made mixins fairly popular. You can do that with a Style Container Query. But just like how Sass had variables then CSS variables turned out to be more powerful and useful, Style Container Queries are likely to be more powerful and useful, because they respect the cascade and can be calculated and such. Support Chrome 'n' Friends Browser Support Safari Firefox Progressive Potentially -- It depends on what you're doing with Enhancement? the styles, but let's say not really. Polyfillable No Basic Demo of Usage CodePen Embed Fallback Container Units What are Container Units? Container Units (literally units, like px, rem, or vw) allow you to set the size of things based on the current size of a container element. Similar to how with viewport units 1vw is 1% of the browser window width, 1cqw is 1% of the width of the container (although I'd recommend you use cqi instead, the "logical equivalent", meaning the "inline direction"). The units are cqw ("container query width"), cqh ("container query height"), cqi ("container query inline"), cqb ("container query block"), cqmin (smaller of cqi and cqb), and cqmax (larger of cqi and cqb). When should you care? If the sizing of anything in an element feels as if it should be based on the current size of the container, container units are essentially the only way. An example of this is typography. A typical Card element may deserve a larger header text when it happens to be rendered larger, without something like a class name needing to be added to control that. (I'm a fan of this demo.) Even a container query is clunky comparatively. Support Browser Full Support Progressive Yes -- you could list a declaration using fallback units Enhancement? right before the declaration using container query units. Polyfillable Yes Basic Demo of Usage This element uses container query units for not only the font-size, but the padding, border, and margin as well. CodePen Embed Fallback The :has() Pseudo Selector What is the :has() selector? The :has() selector allows you to conditionally select an element when elements deeper in the DOM tree of the original element match the selector you put inside :has(). figure:has(figcaption) { border: 1px solid black; padding: 0.5rem; }Code language: CSS (css) When should you care? If you've ever wanted a "parent" selector in CSS, :has() can do that, but it's more powerful than that, as once you've selected the parent you want, you can again drill back down. Jhey Tompkins once called it a "family selector" which a nice way to think about it. You can also combine it with :not() to build a selector when an element doesn't "have" a matching element inside. Support Browser Support Full Progressive Depends on what you're doing with the styles, but Enhancement? let's say not really. Polyfillable For the JavaScript side only Basic Demo of Usage CodePen Embed Fallback View Transitions What are View Transitions? There are two types of View Transitions: 1. Same-Page Transitions (Require JavaScript) 2. Multi-Page Transitions (CSS Only) They are both useful. A same-page transition involves and animation when the DOM is changed without the page changing, like a list being sorted. A multi-page transition is for animating elements between page loads, like a video thumbnail transitioning into a video element. This is the basic syntax for a same-page transition: if (!document.startViewTransition) { updateTheDOM(); } else { document.startViewTransition(() => updateTheDOM()); }Code language: JavaScript (javascript) For multi-page transitions: you need this meta tag: Code language: HTML, XML (xml) Then any element you want to transition between pages you make sure has a totally unique view-transition-name applied in the styles, on both the outgoing page and incoming page. When should you care? Users can understand an interface better if an element moves to a new position rather than instantly being there. There is an animation concept called tweening where the animation is automatically created based on a starting and ending state. View Transitions are essentially tweening. You can control aspects of the animation, but for the most part the animation is automatically created based on the starting and ending state of the DOM, rather than you having to be really specific about the animation details. Support Chrome 'n' Friends Browser Support Safari Firefox Progressive Yes -- the transitions can just not run, or you could Enhancement? provide a fallback animation. Polyfillable No Basic Demo of Usage This is an example of a same-page view transition: CodePen Embed Fallback Nesting What is nesting? Nesting is a way of writing CSS that allow you to write additional selectors within an existing ruleset. .card { padding: 1rem; > h2:first-child { margin-block-start: 0; } footer { border-block-start: 1px solid black; } } Code language: CSS (css) When should you care? Nesting is mostly a CSS authoring convenience, but the fact that it can group related CSS nicely together and prevent you from having to repeat writing a selector can mean avoiding mistakes and making the CSS easier to read. Nested CSS can also be something of a footgun in that may encourage writing CSS that matches the nesting of HTML in an unnecessary way, increasing the specificity and decreasing the reusability of some CSS. .card { container: card / inline-size; display: grid; gap: 1rem; @container (min-inline-size: 250px) { gap: 2rem; } } Code language: CSS (css) The only major difference from Sass-style nesting is that you can't combine the & directly. .card { body.home & { /* totally fine */ } & .footer { /* totally fine, don't even need the & */ &__big { /* nope, can't do this */ } }Code language: CSS (css) Support Browser Support Full Progressive No Enhancement? Polyfillable You could use a processor like LightningCSS, Sass, Less, etc. Scroll-Driven Animations What are Scroll-Driven Animations? Any animation that is tied to the scrolling of an element (often the page itself) can now be done in CSS rather than needing to bind DOM scrolling events in JavaScript. They come in two varieties: * The scroll progress of the element. (animation-timeline: scroll ()) * An element's current viewable position within the element. (animation-timeline: view()) When should you care? Imagine a reading progress indicator bar that fills from 0% to 100% as the user scrolls down the page. That can be done with an animation moving the background-position of an element tried to the overall scroll position of the page. Doing this in CSS instead of JavaScript is good for performance. The other major use case covered by scroll-driven animations is to run an animation as an element enters (or leaves!) the viewport. You have lots of control over the details, like when the animation starts and ends based on how visible the element is. Support Chrome 'n' Friends Browser Support Safari Firefox Progressive Yes -- these effects tend to be visual flair, not Enhancement? required functionality. Polyfillable Yes Basic Example of Usage This is the demo from when we looked at image zooming and page scrolling. CodePen Embed Fallback Anchor Positioning What is Anchor Positioning? Anchor positioning allows you to place items relative to where another element is. Seems pretty obvious when put like that, but that's what it is. You declare an element an anchor and give it a name, then can position elements to the top/right/bottom/left (or center, or the logical equivalents) of the anchor. When should you care? Once you can use this freely, you'll have to care less about exact DOM positioning of elements (aside from accessibility concerns). The way it is now, the element you want to position relative to another has to be a child element and for there to be a positioning context to work within. This can dictate where elements go in the DOM, whether or not that makes sense. The big use cases are going to be tooltips and custom context menus. Support Chrome 'n' Friends Browser Support Safari Firefox Progressive Possibly -- if you can tolerate a totally different Enhancement? position for elements. Polyfillable Yes Basic Example of Usage At the time I'm publishing this, this only works in Chrome Canary with the "Experimental Web Platform Features" flag enabled. CodePen Embed Fallback Scoping What is Scoped CSS? Scoping in CSS is in the form of an @scope at-rule that declares a block of CSS to only apply to the given selector. And optionally, stop applying at another given selector. When should you care? You can also scope CSS by applying a class and nesting within that class. But @scope has a few tricks up it's sleeve that can make it interesting. The "donut scope" option is a unique ability it has: @scope (.card) to (.markdown-output) { h2 { background: tan; /* stop doing this when we get to the Markdown */ } }Code language: CSS (css) More logical proximity styling is another useful feature. This is a bit tricky to explain but once you see it you can't unsee it. Consider theming. You have a .dark selector and a .light selector. If you only ever use one on the entire page, that's fine, but if you end up nesting them at all, because they have the same specificity, whichever one you define later is technically a bit more powerful, and can win out even if it doesn't make sense to. Minimal example: .purple-paragraphs p { color: purple; } .red-paragraphs p { color: red; }Code language: CSS (css)

some text

Code language: HTML, XML (xml) You might think the paragraph element in there would have the color purple, but it will actually be red. That's just awkward, but it can be fixed with @scope. When scoped selectors match, as Bramus says, "it weighs both selectors by proximity to their scoping root", and since "light" is closer here, it would win. My favorite though is the ability to drop in a
Code language: HTML, XML (xml) Support Chrome Browser Support Safari Firefox Progressive Enhancement? No Polyfillable No Basic Example of Usage CodePen Embed Fallback Cascade Layers What are Layers? Cascade Layers in CSS are an extremely powerful syntax that affects the styling strength of a chunk of styles. You can optionally name and order layers (if you don't explicitly order them, they order in source order). Styles in higher layers automatically beat styles in lower layers, regardless of selector strength. Styles not within layers are the most powerful. Code language: HTML, XML (xml) @layer base { body#home { margin: 0; background: #eee; } } body { background: white; } Code language: CSS (css) We're used to thinking that body#home is a much more powerful selector, thus the background will be #eee. But because there are unlayered styles here, that will win, making the background white. You may have as many layers as you like and can order them upfront. I think layering is likely to become a best practice on new greenfield projects, and take shape something like: @layer reset, default, themes, patterns, layouts, components, utilities;Code language: CSS (css) One gotcha is that !important rules on lower layers are actually more powerful. When should you care? One clear way you get a lot of value out of CSS layers if you work on a project that uses a third-party styling library. You can put that library on a lower layer than the styles that your team writes, and you won't have to worry about fighting the third-party library in terms of selector strength. Your styles on a higher layer will always win, which is likely to create cleaner and more maintainable CSS. For example, put all of Bootstrap on a lower layer just using the layer keyword and then any styles you write after that will win, even if Bootstrap itself uses a higher power selector. @import url("https://cdn.com/bootstrap.css") layer; h5 { margin-bottom: 2rem; }Code language: CSS (css) Support Browser Support Full Progressive Enhancement? No Polyfillable Yes Basic Example of Usage CodePen Embed Fallback Logical Properties What are Logical Properties? Logical properties are alternatives to properties that specify a direction. For example, in a left-to-right language like English, the inline direction is horizontal and the block direction is vertical, so margin-right is equivalent to margin-inline-end and margin-top is equivelant to margin-block-start. In a right-to-left language like Arabic, margin-inline-end changes to the equivalent of margin-left, because that is the end side of the inline flow of elements. There are a lot of CSS properties and values that have a directional component like this (border, padding, offset, set), so the trick is understanding inline and block flow and using the correct start or end value. When should you care? Often when you are declaring directional information in CSS, what you mean is "in the inline direction of text". That might sound strange, but imagine a button and the space between an icon and the text. If you apply margin-right to the icon to space it away from the text, but then the page is translated to a right-to-left language, that spacing is now on the wrong side of the icon. What you meant was margin-inline-end on the icon. If you code your side using logical properties in this way, it will automatically translate better without writing any additional conditional code. Support Browser Full Support Progressive You'd have to use @supports and unset to remove the Enhancement? fallback value and reset using a logical property, but it's possible. Polyfillable I can't vouch for it, but there is a processing option. Basic Example of Usage CodePen Embed Fallback P3 Colors What is the Display P3 Color Space? We're largely used to the sRGB color space on the web. That's what hex colors use, and the rgb(), hsl(), and hsb() functions. Many displays these days are capable of display a much wider range of colors than sRGB is capable of describing, so being limited to that color space sucks. The Display P3 color space is about 50% wider than sRGB, expanding in the direction of more rich and vibrant colors. New CSS functions, which can even use different color models that have their own useful properties, allow us to declare colors in this space. When should you care? If you want to use colors that are quite vibrant, you'll need to tap into colors in the P3 Color Space. Using newer color models (and functions) can do this, and are very useful for a variety of other things. For example, the oklch() function (and thus OKLCH color model) can display any color any other method can (plus P3), has a similar human readability in common with hsl(), and has "uniform perceived brightness", so that the first number (lightness) behaves way more predictably than it does in hsl(). That's awfully nice for color on the web. But it's not the only new color model and function! I find the oklab color model generally best for gradients. Support Browser Full (e.g. oklab) Support Progressive Yes -- you can declare fallback colors and displays that Enhancement? can't display the color you declare will come back down into range. Polyfillable Yes Basic Example of Usage You can edit these