缺乏CSS功能以“抑制继承样式”(和背景?)的解决方法

时间:2011-11-10 17:26:36

标签: javascript jquery html css jquery-plugins

我的DOM情况如下:

  • B 的祖先,后者又是 C的祖先

  • 最初, A 的样式会继承 B C

  • 我希望暂时突出显示 B ,为其提供突出显示的

    ... ...然而

  • 我想“逃避” C 上的突出显示,以便尽可能少地改变

在CSS的级联范例中似乎是this is not possible。 “取消应用”样式的唯一方法是应用重写样式。我的问题是突出显示代码在一个插件中,想要与任意页面的现有CSS一起使用...我的选择器是这样的:

/* http://www.maxdesign.com.au/articles/multiple-classes/ */
.highlighted.class1 {
    background-color: ...
    background-image: ...
    ...
}
.highlighted.class2 {
   ...
}
/* ... */
.highlighted.classN {
   ...
}

背景是一个棘手的问题...因为虽然它不是继承的CSS属性,但更改祖先的背景可以改变后代的外观(如果它们具有透明背景)。所以这是一个导致我试图否定的那种破坏的例子。 : - /

是否存在人们如何以这种方式抑制变化的继承?也许使用诸如caching computed styles之类的技巧?我正在寻找任何默认技术,它至少比功能级钩子更聪明一点,它说“嘿,插件突出了这个节点......做你需要的视觉补偿。”


更新我已经创建了这个场景的基本JsFiddle,以帮助使讨论更清晰:

http://jsfiddle.net/HostileFork/7ku3g/

9 个答案:

答案 0 :(得分:4)

如果我理解正确,你想在祖先的背景中切出一个“洞”。 我能想到的唯一方法是使用<canvas>来剪切洞,然后使用生成的图像作为祖先的背景。

这是我的代码:http://jsfiddle.net/7ku3g/24/

我使用JS Fiddle徽标作为水印,因为您无法检索绘制了跨源资源的画布内容。

更新:您还希望收听resize个事件,以便在窗口大小发生变化时更新背景信息。

答案 1 :(得分:2)

正如thirtydot已经指出的那样,背景不是一个继承的属性,而是因为默认情况下子元素是透明的,所以它只是闪耀。所以真正使它们模仿你想要的行为的唯一方法是将它们设置为背景(-image / color),它应用于高亮元素的父(= div#a),甚至低于它。在这个简单的例子中:

.highlight div {
    background-color: white;
}

但在您的真实网站中,这可能不那么容易。

答案 2 :(得分:2)

我有一个解决方案,可以帮助非背景相关的风格。你可以看到小提琴http://jsfiddle.net/7ku3g/83/,它只是一个粗糙的概念。 一些关键点:1)必须将前置styleControl元素添加到最内层元素中。例如,您已将.highlight类添加到.bClass div,但还有另一个完整的包装元素,即blockquote 2)您希望在删除突出显示类后删除styleControl元素。

一般来说,我们的想法是在最里面的包装器中添加一个不可见的样式元素 first ,然后使用常规的兄弟选择器~:not选择器进一步调整样式向下的元素。同样,这并不能解决您的背景问题,但似乎确实是一种帮助解决真正的继承属性的方法,因为这些样式不会应用于包装div,而是应用于新创建的第一个兄弟组和基于兄弟姐妹的属性仅适用于他们需要应用的属性。

这种技术的一个问题是任何“裸文”(参见http://jsfiddle.net/7ku3g/84/)都没有被设计样式。所以它不是你问题的完整解决方案。 编辑:对于这种情况,在这些裸露的节点周围抓取并添加精心设计的span可能会有效。类似于:Style a certain character in a string

CSS

.highlight.bClass  {
    background-image: url('http://hostilefork.com/shared/stackoverflow/cc-by-nc-nd.png');
    background-repeat: repeat;
}

.highlight.bClass .styleControl {
    width: 0;
    height: 0;
    position: absolute;
}

.highlight.bClass .styleControl ~ *:not(.cClass) {
    color: red;
}

更新:根据HostileFork的评论进一步解释。首先,我的解决方案仅限于您希望阻止继承正在添加的样式(实际可继承样式)的子元素。其次,可能需要添加多个,具体取决于嵌套的深度。这里有一些伪代码 html来讨论:

<div> (containing licensed material)
    <childA1> (this is the wrapping blockquote in your example; could be anything)
       <scriptAddedStyleElementB0>
       <childB1>content<endchildB1> (apply styles)
       <childB2>content<endchildB2> (don't apply styles)
       <childB3> (don't apply styles because a child is not having styles applied)
          <scriptAddedStyleElementC0>
          <childC1> (apply styles)
            <!-- noScriptAddedStyleElementD0 -->
            <childD1>content<endchildD1>
            <childD2>content<endchildD2>
          <endchildC1> 
          <childC2>content<endchildC2> (don't apply styles)
       <endchildB3>
    <end-childA1>
<end-div1>

您定位到最外面的div以应用highlight课程,但某些您不希望受影响的孩子。注意A1和B3本身不包含任何内容(文本/图像),它们只包含其他元素。这些是我使用这个术语的“包装”(它们只是用于分组他们的孩子,尽管他们可能自己有造型)。

要回答你的问题“当钻研需要停止时”,那就是当你达到不再关心继承风格的程度时。在上面的例子中,需要添加2个样式元素,一个在B0,一个在C0但不在D0。这是因为通用兄弟选择器~仅适用于具有相同父跟随该兄弟的元素。所以B0将把样式应用于B1而不是B2(非许可)或B3(包含非许可)。元素C0将样式应用于C1(及其许可的子D1和D2),但避免使用样式C2。 B2和C2的内容仍然是从包装div继承原始样式(C2通过B3),而B1,C1,D1,D2都将获得许可样式。

这方面的困难是:1)早期版本的IE(7和8)无法识别某些css,特别是:not选择器。这可能会解决。 2)我之前关于“裸文”或内容的说明。如果B3看起来像:

 <childB3> 
    <scriptAddedStyleElementC0>
    Some unwrapped text
    <childC1>...<endchildC1>
    Some other unwrapped text and an <img> tag
    <childC2>...<endchildC2>
    More unwrapped text
 <endchildB3>

如果B3展开的文本需要设置许可样式(在您的示例中变为红色),那么您需要通过javascript找到所有文本节点并将它们包装在span元素中以应用样式,因为如果你将风格应用于B3,然后它将继承到你不想要的C2。

毫无疑问,您正在寻找的东西很难实现。在一般兄弟选择器出现之前,通过CSS是不可能的,而且正在讨论的CSS4标准可能会变得更容易(能够在这种情况下利用来自子节点的父元素的样式)。

答案 3 :(得分:1)

“背景是一个棘手的问题,因为它有效地继承了它。但它仍然是一个导致我试图否定的那种破坏的例子。: - /”

不正确的。 A ,是最高级元素(最古老的祖先)具有背景。当后续元素来自 A (例如 B C )时,它们具有“透明”的背景,这使得它们看起来具有继承的背景(但这就是为什么你的平铺背景显示为连续的)。

我们可以像@bozdoz所建议的那样,在应用高亮的情况下为子元素使用指定的值,如下所示:

.highlight.bClass #c {
  background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
  background-repeat: repeat;
  color: initial;
}

这会让原始背景的幻觉凝视,并且,鉴于你的例子,肉眼看上去几乎完美无瑕。然而,这具有完全非动态的不幸副作用。例如,我们可能会创建一个新类:

.preventHighlight {
  background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
  background-repeat: repeat;
  color: initial;
}

并且,除此之外,在javascript中添加第二行:

$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#c').toggleClass('preventHighlight');
});

不错。但是,如果它是#x,我们不想突出显示呢?我建议我们为#toggleHighlight提供一个新属性name。在html中,尝试:

<button id="toggleHighlight" name="x">Toggle Highlight</button>

其中name="x"设置为我们希望应用preventHighlight类的元素的ID。因此,我们能够编写更类似于:

的函数
$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#'+$('#toggleHighlight').attr('name')).toggleClass('preventHighlight');
});

您可以继续此操作,而是创建一个带有两个参数的函数,例如 tglHighlight( idToHighlight idToPrevent 你是否如此倾向

修改

我似乎误解了@ bozdoz并完成了同样的事情,却没有注意到背景中的明显变化。我会提出一个轻微的替代方案,其中包括对背景偏移的修正。这仅取决于对我提议的javascript的微小更改:

$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#'+$('#toggleHighlight').attr('name')).toggleClass('preventHighlight');
  $('.preventHighlight').css('background-position', function(index) {
    var ch_pos = $('.preventHighlight').position();
    var a_pos = $('#a').position();
    var x = a_pos.left-ch_pos.left;
    var y = a_pos.top-ch_pos.top;
    console.log( x+"px "+y+"px" );
    return x+"px "+y+"px";
  });
});

答案 4 :(得分:1)

管理javascript中的所有CSS更改,以便它们很容易逆转。正如你所说,纯CSS不可能,但你可以通过javascript缓存样式。

分步骤:

  1. 定义突出显示内容中将忽略哪些元素
  2. 检查您是否在任何父母中都有背景图片
  3. 如果您这样做,请保存图片和该元素的offset()
  4. 抓住后代元素
  5. 保存他们当前的CSS样式(在突出显示之前)
  6. 将突出显示样式应用于目标
  7. 重新应用已保存的后代样式
  8. 如果父母有背景图片,则相应地计算和偏移图像
  9. 这样可以保持内部元素的所有样式不变,并解释“透过”透明背景的背景图像。

    以下是测试:http://jsfiddle.net/W4Yfm/2/

    虽然留下了混乱的风格属性,但你可能想要清理它。可能还有无法获得的边缘情况。

    为了最可靠,你应该使用@Jan指出的技术(在画布上画出高亮显示),但你不会在IE中获得支持&lt; 9,移动设备可能太慢了。

答案 5 :(得分:0)

您可以将.highlight .cClass添加到前两个css组,并在color:initial上设置.highlight .cClass,如下所示:

.aClass, .highlight .cClass {
    background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
    background-repeat: repeat;
}

.aClass, .bClass, .cClass, .xClass, .highlight .cClass {
    border : 2px solid #000;
    margin: 20px;
    padding: 20px;
}

.highlight .cClass {
    color: initial;
}

唯一的问题in this example是背景位置的变化。但这是我提出的最好的。

答案 6 :(得分:0)

检查出来:http://jsfiddle.net/t63m7/

这将适用于jsFiddle中的特定示例案例。您可能需要在实际代码中使用背景位置。

在这种情况下的诀窍是添加以下CSS:

.highlight.bClass div {
    background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
    background-repeat: repeat;
    background-position: -84px 0;
}

答案 7 :(得分:0)

我会将.class的背景设置为与css的.a类相同,但如果你想让它们匹配,你也必须改变背景位置样式。

答案 8 :(得分:0)

嗯,很多建议,但我的第一个想法,我没有测试过,就是给出与你对B级做的任何重点相同的标签,然后制作它!重要。

所以:

.cClass div { 
background-image: none !important; 
}