Posted Jan 11, 2020

If you know anything about web accessibility, then you probably already know that all elements need to have a (or failing that, an aria-supplied label).

What you may not know is what to do when you have something like this:

What do you have for sale? Radio button one says 'spam', radio button two says 'more spam'.

The radio buttons have… two labels. How do you have two labels?

2 labels 1 input

Now you might be forgiven for thinking that the way to solve this problem is as simple as it sounds:

Unfortunately this doesn’t work. According to the spec, a may contain:

Phrasing content, but with no descendant labelable elements unless it is the element’s labeled control, and no descendant label elements.

You also can’t do this:

Unfortunately, the for attribute only takes a single ID.

Great. So now what?

to the rescue

Enter the dynamic duo:



You might already be familiar with the

element as a way to group form controls and labels—that’s the way it’s described on the MDN page—but unfortunately that description is rather disappointingly vague and doesn’t really explain what

is meant for (more on that later). After all, a

groups things together as well—so what’s the big deal aside from the special default styling?

Well, when paired with its sidekick, the

element, it helps screen reader users by providing that second label that we need. Consider the following code:

What do you have for sale?

When a screen reader encounters this code, it will announce the legend to the user along with the label.

Note 1: As per the spec, the

element must be the first child of the


Note 2: screen readers handle this information in slightly different ways though. JAWS will announce the legend for every input in the fieldset, whereas NVDA only announces it upon entering the fieldset. This latter point is something to keep in mind as you design your form, since NVDA users may not realize once they’ve exited the fieldset.

But wait, there’s more!

I mentioned earlier that fieldset elements are meant for something more than just grouping related form controls. Well, strictly speaking that’s true, but we should be more specific about what we mean by “related”. After all, you could argue that most form inputs are related—that’s why they’re part of the same form. So, more accurately, we should say that fieldsets are meant for grouping related form controls that would be unclear or confusing if not grouped.

So what do I mean by that? Well consider a checkout form that asks for both a billing address and a shipping address:

Two sets of address inputs, one for billing address, the other for shipping address.

As a sighted user, I can easily distinguish which “street” input goes with which address, but for a screen reader user this could get confusing in a hurry. So, once again, here comes our superhero element friends to help us out:

Billing Address
Shipping Address

As with before, this may not be perfect for NVDA users due to the way it chooses to handle the legend, but it’s a heck of a lot better than nothing.

What if I don’t want to use



Actually there is a reason you may want to set aside the first rule of ARIA, and not use these elements. Remember how we mentioned earlier that


have default styling? Yeah… about that… it turns out they have very special default styling. This can make it rather difficult to work with, as you usually have to resort to floating and some funky margins to get the result you want.

So if we want to avoid that nonsense then we can achieve a similar result by doing this:

What if I don’t like groups, either?

You know, because you like making life difficult. [sigh]

If you’re unable to wrap your fields in a grouping like this, there are some other ways around the problem. Just note that the drawback to these approaches is that things are going to get a little verbose for your screen reader users, since the full text will be announced for every input (as opposed to the

or group options, where the verbosity is at the discretion of the screen reader software).

For this route, your options are…

Use hidden text

Some aria-labelledby magic on the inputs themselves

Here we can take advantage of the fact that, unlike the for attribute, aria-labelledby can take a string-delimited list of IDs, instead of just a single one.

Billing Address

A good, ol’-fashioned aria-label

Not sure that aria-label qualifies as old-fashioned, but it makes for a good heading. Just be sure that your aria-label includes the same text as the visible label, ideally at the start. This is to ensure that people who use voice control software can focus the input by name.

Wrapping Up

So there you have it. A whole mess of options for ensuring that your form fields are properly identified for everyone.


Say you want to have an image (or any other element) visually float left into a paragraph of text. But like… in the middle of the paragraph, not right at the top. It’s doable, but it’s certainly in the realm of CSS trickery!

One thing you can do is slap the image right in the middle of the paragraph:

Lorem ipsum dolor sit amet consectetur, adipisicing An oak tree. elit. Similique quibusdam aliquam provident suscipit corporis minima? Voluptatem temporibus nulla

But that’s mega awkward. Note the alt text. We can’t have random alt text in the middle of a sentence. It’s semantically blech and literally confusing for people using assistive technology.

So what we have to do is put the image before the paragraph.

An oak tree.

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Similique quibusdam aliquam provident suscipit corporis minima? Voluptatem temporibus nulla

But when we do that, we aren’t exactly floating the image in the middle of the paragraph anymore. It’s right at the top. No margin-top or vertical translate or anything is going to save us here. margin will just extend the height of the floated area and translate will push the image into the text.

The trick, at least one I’ve found, is to leverage shape-outside and a polygon() to re-shape the floated area around where you want it. You can skip the top-left part. Using Clippy is a great way to get a start to the polygon:

But instead of the clip-path Clippy gives you by default, you apply that value to shape-outside.

That should be enough if you are just placing a box in that place. But if it’s literally an image or needs a background color, you might also need to apply clip-path and perhaps transform things into place. This is where I ended up with some fiddling.

See the Pen

Float cutout in middle of paragraph.
by Chris Coyier (@chriscoyier)

on CodePen.


In this post, we’re going to use CSS superpowers to create a visual effect where two elements overlap and weave together. The epiphany for this design came during a short burst of spiritual inquisitiveness where I ended up at The Bible Project’s website. They make really cool animations, and I mean, really cool animations.

My attention, however, deviated from spiritualism to web design as I kept spotting these in-and-out border illustrations.

Screenshot form The Bible Project website.

I wondered if a similar could be made from pure CSS… and hallelujah, it’s possible!

See the Pen

Over and under border design using CSS
by Preethi Sam (@rpsthecoder)

on CodePen.

The principal CSS standards we use in this technique are CSS Blend Modes and CSS Grid.

First, we start with an image and a rotated frame in front of that image.

.design {
  position: relative;
  height: 300px;
  width: 300px;

.design > * {
  position: absolute;
  height: 100%;
  width: 100%;

.rotated-border {
  box-sizing: border-box;
  border: 15px #eb311f solid;
  transform: rotate(45deg);
  box-shadow: 0 0 10px #eb311f, inset 0 0 20px #eb311f;

The red frame is created using border. Its box-sizing is set to include the border size in the dimensions of the box so that the frame is centered around the picture after being rotated. Otherwise, the frame will be bigger than the image and get pulled towards the bottom-right corner.

Then we pick a pair of opposite corners of the image and overlay their quadrants with their corresponding portion in a copy of the same image as before. This hides the red frame in those corners.

We basically need to make a cut portion of the image that looks like below to go on top of the red frame.

The visible two quadrants will lay on top of the .rotated-border element.

So, how do we alter the image so that only two quadrants of the image are visible? CSS Blend Modes! The multiply value is what we’re going to reach for in this instance. This adds transparency to an element by stripping white from the image to reveal what’s behind the element.

Chris has a nice demo showing how a red background shows through an image with the multiply blend mode.

See the Pen

Background Blending
by Chris Coyier (@chriscoyier)

on CodePen.

OK, nice, but what about those quadrants? We cover the quadrants we want to hide with white grid cells that will cause the image to bleed all the way through in those specific areas with a copy of the bird image right on top of it in the sourcecode.

.blend > * {
  position: absolute;
  height: 100%;
  width: 100%;

/* Establishes our grid */
.grid {
  display: grid;
  grid: repeat(2, 1fr) / repeat(2, 1fr);

/* Adds white to quadrants with this attribute */
  background-color: white;

The result is a two-by-two grid with its top-right and bottom-left quadrants that are filled with white, while being grouped together with the image inside .blend.

To those of you new to CSS Grid, what we’re doing is adding a new .grid element that becomes a “grid” element when we declare display: grid;. Then we use the grid property (which is a shorthand that combines grid-template-columns and grid-template-rows) to create two equally spaced rows and columns. We’re basically saying, “Hey, grid, repeat two equal columns and repeat two equal rows inside of yourself to form four boxes.”

A copy of the image and a grid with white cells on top of the red border.

Now we apply the multiply blend mode to .blend using the mix-blend-mode property.

.blend { mix-blend-mode: multiply; }

The result:

As you can see, the blend mode affects all four quadrants rather than just the two we want to see through. That means we can see through all four quadrants, which reveals all of the red rotated box.

We want to bring back the white we lost in top-left and bottom-right quadrants so that they hide the red rotated box behind them. Let’s add a second grid, this time on top of .blend in the sourcecode.

The result!

Summing up, the browser renders the elements in our demo like this:


  1. ​​At bottommost is the bird image (represented by the leftmost grey shape in the diagram below)
  2. ​​Then a rotated red frame
  3. ​​On top of them is a grid with top-left and bottom-right white cells (corners where we don’t want to see the red frame in the final result)
  4. ​​Followed by a copy of the bird image from before and a grid with top-right and bottom-left white cells (corners where we do want to see the red frame) – both grouped together and given the blending mode, multiply​.

You may have some questions about the approach I used in this post. Let me try to tackle those.

What about using CSS Masking instead of CSS Blend Modes?

For those of you familiar with CSS Masking – using either mask-image or clip-path – it can be an alternative to using blend mode.

I prefer blending because it has better browser support than masks and clipping. For instance, WebKit browsers don’t support SVG reference in the CSS mask-image property and they also provide partial support for clip-path values, especially Safari.

Another reason for choosing blend mode is the convenience of being able to use grid to create a simple white structure instead of needing to create images (whether they are SVG or otherwise).

Then again, I’m fully on board the CSS blend mode train, having used it for knockout text, text fragmentation effect… and now this. I’m pretty much all in on it.

Why did you use grid for the quadrants?

The white boxes needed in the demo can be created by other means, of course, but grid makes things easier for me. For example, we could’ve leaned on flexbox instead. Use what works for you.

Why use a data-attribute on the grid quadrant elements to make them white?

I used it while coding the demo without thinking much about it – I guess it was quicker to type. I later thought of changing it to a class, but left it as it is because the HTML looked neater that way… at least to me. 🙂

Is multiply the only blend mode that works for this example?

Nope. If you already know about blend modes then you probably also know you can use either screen, darken, or lighten to get a similar effect. (Both screen and lighten will need black grid cells instead of white.)


It was this:

I say "was" because it's deprecated. It may still "work" (like everybody's favorite in some browsers), but it could stop working anytime, they say. The whole purpose of it was to display text in a monospace font, like the way Teletype machines used to.

Dave used it jokingly the other day.

Per recent events: As you can see by this official transcript, Dave Rupert LLC has done nothing wrong...

Client: This is the greatest call I've ever been on.

Dave Rupert LLC: Definitely and we didn't even do anything illegal or quid pro quo'y.

— Dave Rupert (@davatron5000) September 24, 2019

Which got me thinking how much I used to use that element!

??? pic.twitter.com/lDZpKx9Moy

— Chris Coyier (@chriscoyier) September 24, 2019

Right here on CSS-Tricks. See, in my early days, I learned about that element and how its job is to set text as monospace. I thought, oh! like code! and then for years that's how I marked up code on this site. I had never heard of the element! When I did, I switched over to that. But I still haven't updated every single article from to . It lingers in articles like this:

I bring this up just because it's a funny little example of not knowing what you don't know. It's worth having a little sympathy for people early in their journey and just doing things that get the job done because that's all they know. We've all been there... and are always still there to some degree.


Let’s say you were gonna bounce an element all around a screen, sorta like an old school screensaver or Pong or something.

You’d probably be tracking the X location of the element, increasing or decreasing it in a time loop and — when the element reached the maximum or minimum value — it would reverse direction. Then do that same thing with the Y location and you’ve got the effect we’re after. Simple enough with some JavaScript and math.

Here’s The Coding Train explaining it clearly:

Here’s a canvas implementation. It’s Pong so it factors in paddles and is slightly more complicated, but the basic math is still there:

See the Pen

by Joseph Gutierrez (@DerBaumeister)

on CodePen.

But what if we wanted to do this purely in CSS? We could write @keyframes that move the transform or left/top properties… but what values would we use? If we’re trying to bounce around the entire screen (viewport), we’d need to know the dimensions of the screen and then use those values. But we never know that exact size in CSS.

Or do we?

CSS has viewport units, which are based on the size of the entire viewport. Plus, we’ve got calc() and we presumably know the size of our own element.

That’s the clever root of Scott Kellum’s demo:

See the Pen

Codepen screensaver
by Scott Kellum (@scottkellum)

on CodePen.

The extra tricky part is breaking the X animation and the Y animation apart into two separate animations (one on a parent and one on a child) so that, when the direction reverses, it can happen independently and it looks more screensaver-like.

:root {
  --width: 300px;
  --x-speed: 13s;
  --y-speed: 7s;
  --transition-speed: 2.2s;

.el { 
  width: var(--width);
  height: var(--width);

.x {
  animation: x var(--x-speed) linear infinite alternate;
.y {
  animation: y var(--y-speed) linear infinite alternate;

@keyframes x {
  100% {
    transform: translateX(calc(100vw - var(--width)));
@keyframes y {
  100% {
    transform: translateY(calc(100vh - var(--width)));

I stole that idea, and added some blobbiness and an extra element for this little demo:

See the Pen

Morphing Blogs with `border-radius`
by Chris Coyier (@chriscoyier)

on CodePen.