如何基于dir属性的继承值来创建CSS规则



我知道我可以使用[dir='ltr'][dir='rtl']来选择具有特定值的dir属性的元素。

所以我可以定义例如

 [dir='ltr'] .float-end {float:right}
 [dir='rtl'] .float-end {float:left}

获得一个.float-end类,当在一个分别带有ltr或rtl的元素中时,它会向左或向右浮动。

当我有一个文档的ltr子部分是rtl时,问题就开始了。

<div dir="rtl">
   <div dir="ltr">
      <div class="float-end"></div>
   </div>
</div>

结果是两个规则匹配…在这个场景中,我只想匹配'ltr'的情况。

问题变得更糟,如果我想创建类,如start-20pxend-20px提供left:20pxright:20px,反之亦然,取决于上下文。

会导致left:20pxright:20px同时被应用....

我正在寻找如何克服这个问题的建议。

是否有一种方法依赖于任何给定类型元素的属性的最近值?

如果有帮助的话,这些都是在LESS mixins的上下文中完成的…

Thanks

问题在于CSS中当前可用的属性选择器没有文档语义。例如,您不能使用属性选择器来表示从其他元素继承的某些属性值。这是因为就属性选择器而言,如果元素的属性在文档树中没有在元素本身上指定某个值,那么它将不匹配选择器,即使该值是从其他地方派生的。

如前所述,您可以使用>组合子将选择限制到最近的祖先,但这要求直接祖先具有指定的属性,当然,除非您自己确定,否则您无法保证这种情况。但是,如果您能够修改您的标记,那么这确实是最好的方法,即使这意味着您的标记中有一点冗余。我不认为LESS本身能够帮助你,因为它仍然取决于你的标记结构,这是它无法预测的。

值得注意的是,Selectors 4引入了一个:dir()伪类,它根据文档语言的规则携带元素方向性的语义,这是属性选择器单独无法完成的。例如,以下示例中的divp都将匹配:dir(ltr),但只有div[dir='ltr'],因为p没有指定dir属性:

<div dir="ltr">
    <p>Left-to-right text</p>
</div>

在您的情况下,您将能够分别使用.float-end:dir(ltr).float-end:dir(rtl);你甚至不需要在祖先类上有伪类。

[dir=]属性选择器相比,:dir()伪类类似于:lang()[lang|=],我在这里解释。

当然,作为一个新提案,:dir()并没有在任何地方实现(除了Firefox的奇怪例外-我猜Mozilla想到了这个想法,实现了它,然后提议将其标准化)。与此同时,你将不得不绕过它的路线I des

现在在CSS规范中有一个建议的解决方案:逻辑属性。基本上,浏览器将不再基于其他元素的dir属性应用不同的属性值,而是开始拥有方向感知的属性值。

所以在一个完美的世界里,一旦这些完全支持,你可以写:

.float-end {
  float: inline-end;
}

这些新值将存在于许多属性中,而不仅仅是float。截至2019年7月,除了微软(IE/Edge)之外,几乎所有人都支持。

嗯,我不能给你的第一个问题(关于浮动)的解决方案,但我可以给你一个关于第二个(左/右属性)的解决方案。

w3c

如果'left'和'right'都不是'auto',则位置为过度约束,其中一个必须被忽略。如果包含块的'direction'属性为'ltr',其值为'left'获胜,'right'变成了-'left'。如果"方向"的包含块为'rtl', 'right'优先,'left'被忽略。

好的。因此,在了解到我所期望的并不奏效(至少目前不是[2014年6月])之后,我最终采用了以下基于LESS的解决方案:

//提供一个mixin,根据当前的方向使用两个不同的规则集。

.ltr(@ltrRules) {
  body[dir="ltr"] & , body[dir="rtl"] [dir="ltr"] &, body[dir="rtl"] [dir="ltr"]&  { @ltrRules(); }
}
.rtl (@rtlRules) {
  body[dir="rtl"] & , body[dir="ltr"] [dir="rtl"] &, body[dir="ltr"] [dir="rtl"]& { @rtlRules(); }
}
.bidi(@ltrRules,@rtlRules) {
  .ltr(@ltrRules);
  .rtl(@rtlRules);
}

// padding
// ------------------------------------------
.padding-start(@p) { 
  .bidi(
   { padding-left: @p } ,
   { padding-right: @p }
  )
}

所以使用。padding-start(10;)来选择

.my .selector {
  .padding-start(10px);
}

将最终生成以下CSS:

body[dir="ltr"] .my .selector,
body[dir="rtl"] [dir="ltr"] .my .selector,
body[dir="rtl"] [dir="ltr"].my .selector {
  padding-left: 10px;
}
body[dir="rtl"] .my .selector,
body[dir="ltr"] [dir="trl"] .my .selector,
body[dir="ltr"] [dir="trl"].my .selector {
  padding-right: 10px;
}

折衷方案是,我不能多次改变文档深度的方向,并且必须在body标签上初始看到方向。

也就是说,如果出于一些荒谬的原因,我将在未来的某一点上,当我将不得不更改目录两次以上,我可以使用相同的方法,并为body[dir="ltr"] [dir="rtl"] [dir="ltr"] &等添加处理…

如果运气好的话,几年后有人会明白,添加startend的语义是很重要的,它们分别在LTR上下文中被解释为leftright,反之亦然,在TRL上下文中使我所有的宏都冗余……[就像已经在text-align中做过的那样]。

我知道这是一个很晚的回复,但如果我的问题是正确的,它可以帮助别人。

这有意义吗?

[dir="ltr"] *:not([dir="rtl"]) .float-end,
[dir="ltr"] > .float-end{
    float: right;
}
[dir="rtl"] *:not([dir="ltr"]) .float-end,
[dir="rtl"] > .float-end{
    float: left;
}
这里的

JSFiddle

最新更新