-
-
Notifications
You must be signed in to change notification settings - Fork 72
PostCSS Logical Issues
postcss-logical-properties
worked in a very specific way that lead to multiple issues for users.
How that plugin worked however was also a very powerful feature for many users.
This wiki page is intended to record the classes of bugs and why they happened.
With [dir]
and :dir()
we can not support vertical script.
That means that postcss-logical
becomes a barrier for adoption for specific languages, regions, cultures.
We never intended this and don't think this barrier should exist.
By not using [dir]
or :dir()
and adding support for vertical script we removed this bias from the plugin.
reported in : https://github.com/csstools/postcss-plugins/issues/619
:root {
--size: 1rem;
}
.stage__container {
inset-inline-start: var(--size);
}
becomes :
:root {
--size: 1rem;
}
[dir="ltr"] .stage__container {
left: 1rem;
left: var(--size);
}
[dir="ltr"] .stage__container {
left: 1rem;
left: 1rem;
left: var(--size);
}
.stage__container:dir(ltr) {
left: 1rem;
left: var(--size);
}
[dir="rtl"] .stage__container {
right: 1rem;
right: var(--size);
}
[dir="rtl"] .stage__container {
right: 1rem;
right: 1rem;
right: var(--size);
}
.stage__container:dir(rtl) {
right: 1rem;
right: var(--size);
}
[dir="ltr"] .stage__container {
left: 1rem;
}
.stage__container:dir(ltr) {
left: 1rem;
}
[dir="rtl"] .stage__container {
right: 1rem;
}
.stage__container:dir(rtl) {
right: 1rem;
}
.stage__container {
inset-inline-start: 1rem;
inset-inline-start: var(--size);
}
This bug happens because multiple transforms might be needed to fallback a declaration.
When a plugin like postcss-logical
produces multiple new rules all declarations therein will also be processed again and again by other plugins.
The end result is extreme bloat and broken CSS.
reported in : https://github.com/csstools/postcss-plugins/issues/90
.foo {
margin-inline-start: 10px;
}
/* is transformed into: */
.foo:dir(ltr) {
margin-left: 10px;
}
.foo:dir(rtl) {
margin-right: 10px;
}
.foo:dir(ltr)
is more specific than .foo
. [0 2 0]
vs. [0 1 0]
This leads to subtle bugs.
For example :
li:hover { /* [0 1 1] */
margin-inline-start: 15px;
}
.list-item { /* [0 1 0] */
margin-inline-start: 5px;
}
/* is transformed into: */
li:hover { /* [0 1 1] */
margin-inline-start: 15px;
}
.list-item:dir(ltr) { /* [0 2 0] */
margin-left: 5px;
}
.list-item:dir(rtl) { /* [0 2 0] */
margin-right: 5px;
}
This is definitely an artificial example but it does illustrate how the plugin altered CSS.
- before transforming
li:hover
could match<li class="list-item">
. - after transforming
li:hover
would never match<li class="list-item">
.
.foo {
margin-inline-start: 10px;
}
/* is transformed into: */
.foo {
margin-left: 10px;
margin-inline-start: 10px;
}
left
and inline-start
are only equivalent when the writing mode is horizontal and left to right.
Right to left would render as :
.foo {
margin-left: 10px;
margin-right: 10px;
}
preserve
is intended for transforms that aren't an exact equivalent.
But in this case the preserved declaration contradicts the fallback in certain contexts.