Ana Tudor posted about this recently and I agree: CSS shorthand properties are genuinely useful, but they’re not universally applicable. There are no hard and fast rules here. The question to ask yourself isn’t “can I shorthand this?” but “will someone reading this later, including future me, understand what’s happening?” It comes down to readability and intention, and those are going to look different for everyone. Verbosity isn’t always the enemy.
What’s a shorthand property?
CSS shorthand properties let you set a bunch of related values in a single declaration. There are quite a few of them, some more widely used than others.
One you may be familiar with is the background property, which can set the image source, position, size, repetition rules, origin, color, clip threshold, and scroll behavior all at once:
.selector {
background: url(“/images/my-image.jpg”) 1rem 1rem / 50% 75% no-repeat fixed content-box padding-box orange;
}
Do you know what each of those values corresponds to? Some are obvious. orange is clearly the background color, and the URL is the image. But the numeric values and the content-box/padding-box pair? I have to look those up every single time.
That’s exactly the kind of situation where I’d rather just write it out.
When to use it, when to skip it
When the ordering is intuitive
Directional properties like padding and margin are generally fine to shorthand. I’ve committed the ordering to memory (clockwise from the top side), which is what makes them feel safe. The number of values determines what gets applied.
One value applies to all four sides:
.selector {
padding: 1vw;
}
Two values split into y-axis then x-axis:
.selector {
padding: 1px 10%;
}
Four values apply clockwise from the top (top, right, bottom, left):
.selector {
padding: 1rem 10rem 3rem 2rem;
}
The three-value version, though? I always forget that the second value applies to both right and left. I’d rather write them out individually than trip over that every time I read it back.
So this:
.selector {
padding: 1px 5rem 2rem;
}
Becomes this:
.selector {
padding-bottom: 2rem;
padding-left: 5rem;
padding-right: 5rem;
padding-top: 1px;
}
An even more resilient pattern is to use logical properties rather than strict directional ones, to account for layout changes across different languages and writing modes. In a left-to-right language like English, padding-inline maps to left and right, and padding-block maps to top and bottom. In a right-to-left language like Arabic, the inline axis flips.
You can get more specific with padding-inline-start, padding-inline-end, padding-block-start, and padding-block-end to target individual sides. In this example, a left-to-right reader sees 2rem on the left and 6rem on the right; a right-to-left reader sees those values swapped, with the same top and bottom padding either way:
.selector {
padding-block: 10%;
padding-inline-start: 2rem;
padding-inline-end: 6rem;
}
border-radius falls into this category, too. One value applying to all four corners is intuitive enough that shorthand may be fine:
.selector {
border-radius: 8px;
}
And when we have a variety of values, it’s good to know what we intend with longhand syntax. Sometimes I’ll even write out a zero-ed out property (like border-bottom-right-radius) in this example to communicate exactly what’s needed for this element’s shape:
.selector {
border-top-left-radius: 2rem;
border-top-right-radius: 8rem;
border-bottom-right-radius: 0;
border-bottom-left-radius: 5px;
}
When each value is a distinct type
transition and animation are both shorthands that pack in a lot: duration, easing, delay, and the property being targeted. For simple cases, the shorthand may hold up when each value is a distinct type: a name, a duration, an easing function.
This example may be easier to parse without ambiguity:
.selector {
animation: spin 1s ease-in-out;
}
But even when the types are distinct, ordering can become its own problem at scale. If one part of a codebase has:
.selector {
animation: spin 1s ease-in-out;
}
And another one has:
.selector {
animation: linear fade 2s;
}
Both are valid, but the inconsistency means you’re re-parsing the order every time you encounter the shorthand. Writing them out individually enforces a consistent structure by default. There’s no order to forget or vary.
When things get specific with different delays per property or timing, I’ll pull out the individual properties anyways. Ana’s post has a great example of this: if you have multiple properties transitioning at the same duration, writing the full shorthand for each one is just repeating yourself:
.selector {
animation: 1s ease-in-out;
animation-name: spin, fade;
}
animation in particular has enough sub-properties (animation-fill-mode, animation-iteration-count, animation-direction, and more) that the shorthand may get unwieldy fast. In practice, once I’m reaching for any of those, I just write them out all individually.
When the syntax has its own rules
Some shorthands have parsing rules specific enough that you may need to have the spec loaded to read them. These are the ones I almost always write out.
background is my go-to example. Unless you’re setting something dead simple like a solid color or a plain image, the full shorthand becomes a puzzle. This is still readable:
.selector {
background: url("/images/my-image.jpg") no-repeat center / cover;
}
But once you’re reaching for position offsets, size, origin, and clip together, the shorthand stops carrying its weight:
.selector {
background: url("/images/my-image.jpg") 1rem 1rem / 50% 75% no-repeat fixed content-box padding-box orange;
}
It fails here not because there are many values, but because the values are opaque without knowing the specific syntax. The / separates position from size, so 1rem 1rem / 50% 75% isn’t four coordinates, it’s two pairs with different meanings. The content-box padding-box pair sets origin and clip in that order, which isn’t something you can always intuit. And that’s a different problem from padding having too many values, because at least those follow a spatial logic.
.selector {
background-attachment: fixed;
background-clip: padding-box;
background-color: orange;
background-image: url("/images/my-image.jpg");
background-origin: content-box;
background-position: 1rem 1rem;
background-repeat: no-repeat;
background-size: 50% 75%;
}
border is also interesting because it’s a layered shorthand situation: border is a shorthand, and so is border-left. The catch is that border applies to all four sides. You have to go down to the directional properties or the individual sub-properties to set different sides. I usually write border shorthand when I want a consistent border all the way around, but I’ll break it out when I’m doing something more specific with colors or styles on individual sides.
You can also write the sub-properties directionally, which is a nice middle ground:
.selector {
border-color: red blue green yellow;
border-style: solid dashed;
border-width: 10px 3px 50px;
}
grid falls into this category too. The shorthand syntax can be genuinely hard to parse at a glance:
.selector {
grid: auto-flow dense 40px / repeat(3, 1fr);
}
This feels easier to read to me:
.selector {
grid-auto-flow: dense;
grid-auto-rows: 40px;
grid-template-columns: repeat(3, 1fr);
}
I write grid and flex out fully, almost every time.
When you can’t retain it
Some shorthands just don’t stick, and that’s reason enough to write them out. This is also an honest admission that the thresholds I’m describing aren’t necessarily universal; they’re shaped by what I’ve internalized over time. These are conditions as I experience them and not objective rules.
I use the longhand syntax for text-decoration more often than not, even though the individual property names are fairly obvious. I just can’t seem to retain the shorthand structure.
I always have to think about this:
.selector {
text-decoration: underline dotted red 2px;
}
And to me, this syntax reads like a list of decisions:
.selector {
text-decoration-color: red;
text-decoration-line: underline;
text-decoration-style: dotted;
text-decoration-thickness: 2px;
}
gap is another directional one: it only deals with row gap and column gap in CSS grid. I usually set the same value for both, so shorthand is fine. But when they’re different, I’ll often write row-gap and column-gap separately, mostly because I can never remember which order they go in. I’ve somehow committed padding and margin to memory but not this one.
font I have literally never written shorthand in my life. It just doesn’t feel natural, especially with font-family, which often has spaces and fallback stacks and needs its own line anyway.
font-variant is a fancy one I reach for when handling special typefaces, usually for turning on ligatures. I can never remember all the individual values, so I write them out. And since I’m typically only tweaking one or two things, it doesn’t add much overhead.
It’s not all or nothing
You don’t have to choose between going full shorthand or writing out every individual property (spoiler though: I often do make that choice). You can mix them by using the shorthand to set a baseline and then applying a specific longhand when you need precision for one value.
border is a solid example of this. Set the baseline with shorthand, then override what changes in a variant:
.button {
border: 2px solid navy;
}
.button--destructive {
border-color: red;
}
The goal is always clarity. Use the version that makes your intent most obvious.
Writing only what you mean
Despite what I’ve just written in the previous section, I don’t usually mix short and longhand and am most often choosing the latter.
Longhand can communicate scope, and is a key reason I often err on that side rather than brevity.
Even for something as simple as background color, I’d rather write:
.selector {
background-color: green;
}
Instead of:
.selector {
background: green;
}
The shorthand works, but leaves the door open. If I only mean to set a color, background-color says that plainly and there’s no slot for anything else other than that to accumulate.
The same logic applies when I want a handful of sub-properties. If I only want a selector to have a background image, color, and repeat value, I write exactly those three properties:
.selector {
background-color: #b4da55;
background-image: url(“images/my-image.jpg”);
background-repeat: no-repeat;
}
A background shorthand would create a natural place for other sub-properties to creep in. Someone (including future me) might reasonably add background-size or background-position to that declaration later. And while those are fine additions, it signals intention to me when they’re written out as their sub-properties instead of values within the shorthand.
At the end of the day, shorthand properties are a tool, not a mandate. And if your answer differs from mine: yeah, well you know, that’s just like uh, your opinion, man.