elchininet / postcss-rtlcss

PostCSS plugin to automatically build Cascading Style Sheets (CSS) with Left-To-Right (LTR) and Right-To-Left (RTL) rules using RTLCSS
https://elchininet.github.io/postcss-rtlcss/
Apache License 2.0
102 stars 15 forks source link

How can I make a direction ignored when another is present? #414

Open 313ava opened 1 day ago

313ava commented 1 day ago

Hi, I have a rtl dir in my HTML tag and some divs with ltr directions. I want to prevent ltr divs have rtl styles as well. Is there a way? In fact some part of my view should be in ltr when others should be rtl. The problem comes when an element with absolute position and a left or right value is present and it takes both left and right values instead of one.

elchininet commented 1 day ago

Hi @313ava,

That is a question not related to the plugin itself, but it is more a question about CSS cascading behaviour and how to avoid an element being affected by two different rules.

You want to have a dir attribute in your root element that affects any element on the page excluding those that have a parent element with a dir attribute, in those cases the second one should rule over the first. You should check how to do that by hand and then try to build a solution using the plugin.

There could be multiple solutions for that, but this is the first one that comes to my mind.

Imagine that you have the next rule:

.example {
  left: 10px;
}

You can achieve your goal in the next way:

[dir="ltr"]:root .example:not([dir]:root [dir] .example),
[dir]:root [dir="ltr"] .example {
  left: 10px;
}

[dir="rtl"]:root .example:not([dir]:root [dir] .example),
[dir]:root [dir="rtl"] .example {
  right: 10px;
}

In that way, if the html has a dir property and the element is inside another element with a dir property, the dir property of that element will rule over the dir property of the html. The dir property of the html will be applied only if there is no element in the tree with a dir property.

Take into account that this will work if there is only one level of dir overriding. If you have multiple elements in a tree with different dir properties you will need to build more selectors to cover those cases.

To achieve the previous approach you would need to build your own logic to prefix the selectors. You need to use custom ltrPrefix and rtlPrefix options together with the prefixSelectorTransformer option to build a custom rule prefixer.

This is just a simple example that will not cover all the use cases, but it is just to show you how these properties work. You will need to cover special cases like html or :root selectors as well as cases with pseudo-elements in the selectors:

{
  ltrPrefix: ['[dir="ltr"]', 'ltr'],
  rtlPrefix: ['[dir="rtl"]', 'rtl'],
  prefixSelectorTransformer: (prefix, selector) => {
    if (prefix === '[dir="ltr"]' || prefix === '[dir="rtl"]') {
      // Return the selector with no elements with a dir attribute in the tree
      return `${prefix}:root ${selector}:not([dir]:root [dir] ${selector})`;
    }
    // Return the selector for an element in the tree with a dir property
    if (prefix === 'ltr' || prefix === 'rtl') {
      return `[dir]:root [dir="${prefix}"] ${selector}`;
    }
  }
}
313ava commented 22 hours ago

thanks, I checked your suggest but not worked! I think if we could say the plugin to be important in ltr against rtl, it solved.

elchininet commented 20 hours ago

Hi @313ava, Remember what I mentioned:

You should check how to do that by hand and then try to build a solution using the plugin.

So you need to define what you mean with "not worked".

Is the approach using the selectors that I proposed not working? If that is the case explain what is not working.

If what is not working is your custom prefixer, remember that what I gave you is a proof of concept, not a working code, you would need to do that by yourself depending on your CSS code. If you have issues writing your custom prefixer just post your results and what the prefixer is doing and I can help you out.

I think if we could say the plugin to be important in ltr against rtl, it solved.

What do you mean with "the plugin to be important in ltr against rtl"? Do you mean to add !important statements on each ltr prefixed rule? If that is what you are proposing, that will not solve your issue. There is no need for important statements in this case, if you make a prefix more specific it will rule over the other. But your issue is another one:

Making a left: 10px !important will not make that a right: 10px goes away

If you are trying to propose another thing just explain how you would make "the plugin to be important in ltr against rtl".

Regards