A guided tour of cutting-edge CSS you can use now
Welcome to a tour of cutting-edge CSS you can use now. These examples were inspired by this article: 5 CSS snippets every front-end developer should know in 2024. Front-end web developer Teri Shelton, in collaboration with designer Andy Krikawa, put together these examples.
At the May 21, 2024 Front-End Tech Community of Practice, we'll demonstrate how they work and share some ideas on use cases. There's so much to cover: from subgrid to container queries and :has() to color-scheme... and more! It's going to be like a guided tour of favorite sites: stop, look at the view, snap a photo (screenshot!), ask a question, hop back on the bus.
Balance headlines & text
Balance headlines and small amounts of text automatically to have more balance across multiple lines (balance
) and not have orphans (pretty
).
Balance is only supported for 6 or fewer lines in Chromium and 10 or fewer lines in Firefox.
Adjust your window size to see how these examples wrap differently based on their text-wrap
property.
This is a sample headline that is completely normal - nothing to see here
Cat ipsum dolor sit amet, meow meow you are my owner so here is a dead bird cats making all the muffins. Paw your face to wake you up in the morning.
This is a sample headline with balanced text wrap set to balance
Cat ipsum dolor sit amet, meow meow you are my owner so here is a dead bird cats making all the muffins. Paw your face to wake you up in the morning.
This is a sample headline with balanced text wrap set to pretty
Cat ipsum dolor sit amet, meow meow you are my owner so here is a dead bird cats making all the muffins. Paw your face to wake you up in the morning.
To enable these text-wrap
options:
.balance {
text-wrap: balance;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
.pretty {
text-wrap: pretty;
}
Object fit
Move over background-image
! Now we can use { object-fit: cover; }
to get a similar result. It makes an image behave like a background image, but with the advantage of retaining the semantics of an img
tag. We can also use { object-fit: scale-down; }
. The image acts as a container for its own contents.
Images set inside some custom (non-Bootstrap) cards

Custom card 1
I'm a custom card and the intrinsic size for the image I'm holding is 300x200.

Custom card 2
I'm a custom card and the intrinsic size for the image I'm holding is 125x188.

Custom card 3
I'm a custom card and the intrinsic size for the image I'm holding is 400x400.
img {
/* nothing set...image will break outside of its containing element, if it needs to */
}
Images set inside custom cards, but better

Custom card 1
I'm a custom card and the intrinsic size for the image I'm holding is 300x200.

Custom card 2
I'm a custom card and the intrinsic size for the image I'm holding is 125x188.

Custom card 3
I'm a custom card and the intrinsic size for the image I'm holding is 400x400.
img {
object-fit: cover;
width: 100%;
}
And taking it one step further

Custom card 1
I'm a custom card and the intrinsic size for the image I'm holding is 300x200.

Custom card 2
I'm a custom card and the intrinsic size for the image I'm holding is 125x188.

Custom card 3
I'm a custom card and the intrinsic size for the image I'm holding is 400x400.
img {
object-fit: cover;
width: 100%;
border-radius: 1em 1em 0 0;
height: 50%;
object-position: center bottom;
}
Aspect ratio
Aspect ratio can be an incredibly handy tool to resolve traditionally frustrating layout situations.
As you can see with the image examples below, aspect-ratio
used alone may not be your best bet, but combined with object-fit
and object-position
, can guarantee you will always have the same layout.
Normal responsive image

img {
width: 100%;
height: auto;
}
16:9 aspect ratio

img {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
}
1:1 aspect ratio

img {
width: 100%;
height: auto;
aspect-ratio: 1 / 1;
}
Here are the same examples with object-fit
and object-position
also applied:
Normal responsive image

img {
width: 100%;
height: auto;
}
16:9 aspect ratio

img {
width: 100%;
height: auto;
object-fit: cover;
object-position: center;
aspect-ratio: 16 / 9;
}
1:1 aspect ratio

img {
width: 100%;
height: auto;
object-fit: cover;
object-position: center;
aspect-ratio: 1 / 1;
}
Getting into video, iframes in particular, is where things have traditionally been annoying and frustrating to wrangle. With aspect-ratio, you can ensure your video is always the same aspect ratio regardless if the window or screen size.
Normal YouTube embed - fixed width & height
<iframe width="560" height="315"
src="https://www.youtube.com/embed/3Mcm4ko6Mgw"
title="YouTube video player"></iframe>
YouTube embed with fixed width and aspect ratio 1/1
<iframe width="500"
src="https://www.youtube.com/embed/3Mcm4ko6Mgw"
title="YouTube video player"></iframe>
iframe {
aspect-ratio: 1 / 1;
}
YouTube embed with aspect ratio 16/9
<iframe src="https://www.youtube.com/embed/3Mcm4ko6Mgw"
title="YouTube video player"></iframe>
iframe {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
}
Margin inline
margin-inline
is a shorthand for setting the inline margin (aka, the left and right margin for horizontal writing modes). To demonstrate the benefits, I've thrown in a few more logical properties in these examples. Logical properties were new to me!
The long form way
This is a customized card that's left aligned. It has an image avatar, some text and a solid left border.
This is a customized card that's right aligned. The card has direction: rtl;
set for its contents. It has a solid right border.
For the first example above I added some styles to the .card
wrapper:
.card {
padding-left: 1.5em;
padding-right: 1em;
border-left: 1.5em solid #4b2e83;
}
img {
margin-right: 1em;
}
Then, for second example (assuming direction: rtl;
is set), some styles needed to be reset and others added:
.card {
padding-right: 1.5em;
padding-left: 1em;
border-left: 0;
border-right: 1.5em solid #4b2e83;
}
img {
margin-right: 0;
margin-left: 1em;
}
Now with logical properties
This is a customized card that's left aligned. It has an image avatar, some text and a solid left border.
This is a customized card that's right aligned. The card has direction: rtl;
set for its contents. This has a solid right border.
For both the examples directy above, this is all that was needed:
.card {
padding-inline-start: 1.5em;
padding-inline-end: 1em;
border-inline-start: 1.5em solid #4b2e83;
}
img {
margin-inline-end: 1em;
}
Text underline offset
We now have text-underline-offset
which controls the distance of the underline from the text (which is coming from text-decoration: underline
).
Some "older" ways
- See video of Dubs - do nothing and take the default, which is:
{ text-decoration: underline; }
- See video of Dubs - remove the default and use border-bottom
{ text-decoration: none; border-bottom: 1px solid }
- See video of Dubs - remove the default and use a box-shadow and put padding around the link:
{ text-decoration: none; box-shadow: 0 3px; padding: 4px; }
What the cool kids are using now
- See video of Dubs - decide how far from the text you want the underline like:
{ text-underline-offset: .25em; }
- See video of Dubs - pair it with text-decoration-thickness, so:
{ text-underline-offset: .25em; text-decoration-thickness: 0.2em; }
- See video of Dubs - go far with the offset and thicken up the border (probably not the best idea?) with
{ text-underline-offset: .5em; text-decoration-thickness: 0.3em; }
Outline offset
Adding outline-offset
to an element pushes the outline away by the value you give the property. Using a negative value pulls the outline into the element.
The general idea
This has a positive offset This has a negative offset
Links in a paragraph
This first link has no outline-offset on focus! Here's some more text so we can see it in action among other links that have outline-offset on focus. And were we to keep tabbing through a paragraph - here's a link to another place.
Buttons
Here are some things we can do with buttons and adding outline-offset on focus.
Scroll margin top/bottom
Scroll margin (scroll-margin
) sets the scroll margins of an element inside its container. Each child element of a container has a snap position. scroll-margin
lets us tinker that position as if the child element has a margin.
Child elements stacked vertically
What's going on here, in a nutshell:
.scroll-container {
.box-1 {scroll-margin: 0;}
.box-2 {scroll-margin: 1em;}
.box-3 {scroll-margin: 2em;}
.box-4 {scroll-margin: 0;}
.box-5 {scroll-margin: 4em;}
.box-6 {scroll-margin: 0;}
}
On this page
These elements don't have a scroll-margin
.
These two elements do have a scroll-margin
of 8em
.
Here's where scroll-margin
is in play:
#object-fit,
#text-wrap-balance {
scroll-margin-top: 5em;
}
Accent color
The accent-color property currently works on input elements for checkbox, radio, and range, and the progress element.
Note the background color on the progress and range elements is set automatically based on the color specified.
Default
Accent color specified
Accent color specified
To enable accent color:
.accent1 {
accent-color: pink;
}
.accent2 {
accent-color: #4b2e83;
}
Fit content width
Instead of display: inline-block;
to have an element's width match its content's size, you can use width: fit-content
to achieve the same. This leaves the display
property open for other use. The computed box size adjusts to the dimensions created when using fit-content
.
The wrapper fills the available space.
The wrapper fits the content because we're using width: fit-content
.
CSS Nesting
Basically, like nesting in Sass or LESS, but parsed by the browser instead of compiled a preprocessor. If you are familiar with Sass, this will be almost identical.
Here's an example from this site's stylesheet:
body {
#accent-color {
.accent1 {
accent-color: pink;
}
.accent2 {
accent-color: var(--wp--preset--color--husky-purple);
}
}
}
The browser essentially converts this to:
body #accent-color .accent1 {
accent-color: pink;
}
body #accent-color .accent2 {
accent-color: var(--wp--preset--color--husky-purple);
}
Also check out what it looks like in the dev tools with the nesting.
:has()
From MDN: "The functional :has() CSS pseudo-class represents an element if any of the relative selectors that are passed as an argument match at least one element when anchored against this element. This pseudo-class presents a way of selecting a parent element or a previous sibling element with respect to a reference element by taking a relative selector list as an argument."
A parent selector
In this example, we are adding a top margin only if the card has an image. This creates a more uniform style for when the card doesn't have an image. We're using an exaggerated margin on the image cards to easily see a difference.

Card title
Some quick example text to build on the card title and make up the bulk of the card's content.
Go somewhere
Card title
Some quick example text to build on the card title and make up the bulk of the card's content.
Go somewhereCard title
Some quick example text to build on the card title and make up the bulk of the card's content.
Go somewhere.card:has(img) {
h2, h3, h4, h5, h6 {
margin-top: 2rem;
}
}
Change parent and child based on parent contents
In this example we'll apply different styling to an image based on whether it has a caption.
Example without caption
Cupcake ipsum dolor sit amet cotton candy powder liquorice shortbread. Croissant macaroon dessert danish caramels donut caramels. Candy canes apple pie gummi bears tootsie roll cookie.

Liquorice bear claw shortbread toffee muffin. Brownie pudding pudding candy cake. Bonbon powder macaroon soufflé lollipop. Bonbon topping chocolate bar chocolate bar tart oat cake marshmallow.
Example with caption
Cupcake ipsum dolor sit amet cotton candy powder liquorice shortbread. Croissant macaroon dessert danish caramels donut caramels. Candy canes apple pie gummi bears tootsie roll cookie.

Liquorice bear claw shortbread toffee muffin. Brownie pudding pudding candy cake. Bonbon powder macaroon soufflé lollipop. Bonbon topping chocolate bar chocolate bar tart oat cake marshmallow.
/* All images */
.text-image {
border: 1px solid var(--wp--preset--color--spirit-pink);
padding: 1rem;
img {
width: 100%;
height: auto;
margin-bottom: 1rem;
}
}
/* Images with figcaptions, style the container and change the image styling */
.text-image:has(figcaption) {
border: 1px solid var(--wp--preset--color--spirit-teal);
background-color: #efefef;
figure {
border: 1px solid var(--wp--preset--color--spirit-candle-green);
padding: 1rem;
background-color: white;
img {
margin-bottom: 0.5rem;
}
figcaption {
font-style: italic;
font-weight: bold;
}
}
}
Show an error message outside your form if something happens inside your form, using only CSS
This example shows how you can toggle content based on form actions without using JavaScript.
Check the "Agree to terms and conditions" box below to see the example error message.
Hello! Only show me if the box is checked!
First, let's see our markup:
<div class="form-example">
<div class="error alert alert-danger">
<p>Hello! Only show me if the box is checked!</p>
</div>
<form class="row mt-5 mb-5 g-3 needs-validation" novalidate>
...
</form>
</div>
</div>
And here is the CSS to make this work:
.form-example:has(input:checked) {
.error {
display: block;
}
}
.form-example:not(:has(input:checked)) {
.error {
display: none;
}
}
💡 Tip: additional functional pseudo-classes
:is()
, :where()
, and :not()
are the other functional pseudo-classes. They can be used with :has()
and each other. Have you used these yet?