-
-
Notifications
You must be signed in to change notification settings - Fork 83
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:hovercould match<li class="list-item">. - after transforming
li:hoverwould 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.