A Better Way to Write Positions in CSS
One of the more cumbersome things to write in CSS is position offsets.
.cover-something {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Have you ever had to write something like that? Some of us even try to sort our properties alphabetically.
.cover-something {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
Yikes! Once we stuff more properties into that rule, whatever concept we had hoped to convey is probably lost.
This weekend, I was pleasantly surprised to see the CSSWG tackling this issue.
We need a name for a shorthand for the top/left/bottom/right properties. Ideas?
— @csswg
Shorthands? I love shorthands! Immediately, there was a great suggestion to
extend the position
property.
1. Make position a shortcut, e.g. `position: absolute 1px 7px 9px 1px`. 2. Add long name for current position (e.g. position-mode).
— @ashmind
The gist of that means position
would accept clockwise values, just like
margin
and padding
. This means shorthand values like:
.cover-something {
position: absolute 0;
}
Pretty clean, huh! However, the CSSWG reminded us of one very important reason this can’t ever happen.
We can't make an existing property a shorthand for a property it doesn't currently shorthand, because then it would reset that property.
— @csswg
Good grief. Very well, the next suggestion was to use a new property — offset
.
.cover-something {
offset: 0;
position: absolute;
}
But that bubble was also burst pretty quickly.
Issue is that the current proposal, 'offset', conflicts with the properties in https://drafts.fxtf.org/motion/
— @csswg
Ugh. Fine! What if we hypenate it?
box-offset
— @valtlai
I really like this.
With box-offset
, we might have something to work with. Well done, everyone!
But we’re not out of the woods yet. Jake Archibald reminded us of a weakness with those clock-wise shorthand properties.
Put it this way: I frequently set top & left together. I sometimes set all to 0, but aside from that, I rarely want t/b l/r to be the same.
— @jaffathecake
Setting the top
and left
properties would mean developers choose between
writing 2 longhand properties or resetting all offsets to use the shorthand.
.inset-from-the-top-left {
offset: 10px auto auto 10px;
position: absolute;
}
That doesn’t look super great. Shorthands overwrite everything, which means any
previous right
or bottom
properties would have to be redeclared. Also, if
top
and left
are meant to convey the same value, the visual separation
means that concept is somewhat lost.
Still, these are all problems we already deal with when using margin
or
padding
.
I think we could define a non-destructive shorthand that preserves offset
relationships. It might even let us use position
.
The secret lies in CSS Grids.
.container {
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}
Those words in the brackets represent something called “custom identifiers”. So, what if we applied custom identifiers to position offsets?
.inset-from-the-top-left {
position: absolute [top left] 0;
}
.cover-everything {
position: absolute [top right bottom left] 0;
}
Pretty clear, I think. Still, that second example is not zesty. Maybe we could just omit the names when writing all of them.
.cover-everything {
position: absolute [] 0;
}
And why bother with writing out full names anyway?
.inset-from-the-top-left {
position: absolute [tl] 0;
}
That looks useful.
And remember, none of this requires us to re-use the position
property.
This idea could still work with box-offset
!
Okay, nerd alert. I don’t know about you, but when I try to imagine future web standards I also try to apply everything I know about other emerging standards.
For instance, I understand we’re trying to get away from the whole left
and
right
thing and instead call it inline start
and inline end
. Similarly,
top
and bottom
are block start
and block end
. Well, good news — our
identifier pattern still works!
.inset-from-the-top-left {
position: absolute [block-start inline-start] 0;
}
Or why not:
.inset-from-the-top-left {
position: absolute [start] 0;
}
Or hey why not:
.inset-from-the-top-left {
position: absolute [s] 0; /* aww yiss */
}
All together, if we adopt this block/inline + start/end syntax, we get the following identifiers:
Position Offset | Identifier | Legacy Properties |
---|---|---|
inline | i |
left ,right |
block | b |
top ,bottom |
start | s |
left ,top |
end | e |
right ,bottom |
inline start | is |
left , |
inline end | ie |
right |
block start | bs |
top |
block end | be |
bottom |
inline start + block | isb |
left ,top ,bottom |
inline end + block | ieb |
right ,top ,bottom |
inline + block start | ibs |
left ,right ,top |
inline + black end | ibe |
left ,right ,bottom |
all offsets | (empty) | left ,right ,top ,bottom |
Do you think this could solve real problems? What sorts of problems do you think it might create?