13

有人知道使用 CSS 更改多层背景的一层的方法吗?

我一直在四处寻找,但找不到任何提及当前甚至提议的未来规范的内容。我的想法是可能不会有,但是现在网络如此庞大,我确信某个地方的某个人拥有这些信息或讨论的链接。

以下示例在应用于不同元素时显然会在优先顺序方面存在问题:

.building-texture {
  background: transparent, url(image/building-side.png);
}

.shade-dark {
  background: url(image/shade-dark.png), unchanged;
}

.shade-mid {
  background: url(image/shade-mid.png), unchanged;
}

.shade-light {
  background: url(image/shade-light.png), unchanged;
}
<div class="building-texture shade-dark"></div>

显然,上面有许多解决方法,但没有一个是理想的,尤其是当您开始谈论许多不同的“层状态”和许多不同的“纹理”时:

初步解决方案

组合班

这是最理想的后备方案,但是当您开始考虑供应商前缀并处理两个以上的层时,它会变得很荒谬。

.building-texture-shade-dark {
  background: url(image/shade-dark.png), url(image/building-side.png);
}

.building-texture-shade-mid {
  background: url(image/shade-mid.png), url(image/building-side.png);
}

.building-texture-shade-light {
  background: url(image/shade-light.png), url(image/building-side.png);
}

单独的元素

在本地运行一些测试时,我发现多层背景比使用子元素执行得更快。事实上,对于大多数现代浏览器来说,即使引入一个简单的孩子(没有应用背景)也会大大减慢渲染速度。

<div class="building-texture">
  <div class="shade-dark"></div>
</div>

JavaScript 生成

为了克服手动输入第一个选项(组合类)的痛苦,可以使用 JavaScript 来生成样式表。但是你仍然有长类名的尴尬。另外,当您想要更改组合类的一个应用效果(例如删除阴影)时,您必须编写脚本以根据命名约定确定如何执行此操作。

通过 JavaScript 设置样式属性

另一种选择是通过.style每个元素动态重写整个背景。我还没有对此进行测试,但我的头脑告诉我这将是相当低效的,因为我确信浏览器在处理预设类时能够进行相当多的优化(即通过按分类对元素渲染进行分组)。虽然我可能是错的。

为什么...

我正在玩 CSS 3D 变换(启用透视)以及如何以简单快速的方式最好地纹理/照亮此类结构(示例代码):

http://pebbl.co.uk/wote/

示例图像
(来源:pebbl.co.uk

在未能生成我满意的 CSS 解决方案后,我目前正朝着基于 Canvas 的解决方案前进,该解决方案将预先构建我可能想要的所有纹理以及它们不同的阴影状态,然后生成缓存数据 URI附加为单层背景。我的测试表明这是最佳的。但是,我真的很想使用尽可能多的基于浏览器的原生解决方案,因为使用画布涉及更多的代码,而且,因为今天的浏览器改进得如此之快,重新发明任何轮子、引擎、或道路网络。

即使可能被认为我所做的不是对 CSS 的“正确”使用,在我看来,每个背景项目都是它自己的单元——对我来说,应该有一些指定的方式来修改每个背景项目是有道理的单独的单元......即使它在未来很遥远。

我会对任何带有这些讨论链接的答案感兴趣。

4

2 回答 2

4

不幸的是,在常规 CSS 中没有办法做到这一点。您只能更改整个属性,而不是其中的一部分。这就是为什么我们有单独的属性,比如background-image,background-color开始。但没有比这更细粒度的了。

正如 ScottS 所建议的,伪元素可能是一种方法,但您可能会遇到与多个单独的 div 元素相同的问题。

如果您的主要目标是避免一遍又一遍地输入代码,一个好的解决方案是使用 CSS 预处理器,如SASS。您的 SCSS 将是这样的:

$img-side:  url("image/building-side.png");
$img-dark:  url("image/shade-dark.png");
$img-mid:   url("image/shade-mid.png");
$img-light: url("image/shade-light.png");

.building-texture {
  background: transparent, $img-side;
}    
.shade-dark {
  background: $img-dark, $img-side;
}    
.shade-mid {
  background: $img-mid, $img-side;
}    
.shade-light {
  background: $img-light, $img-side;
}

它会编译成更庞大的 CSS(带有完整的 URL 定义),但您肯定会节省很多开发时间。SASS 还可以帮助您使用 mixins 生成供应商前缀(还有 Compass 将其添加到 SASS)。

事实上,有一个即将发布的 CSS 变量规范,您将来可能会使用它,但我认为目前还没有任何浏览器支持它。

于 2013-01-21T15:33:00.430 回答
3

用伪元素抽象它

我还不知道有任何方法可以“交换”单个背景。一种解决方法是基于“分离元素”技术,但内部元素是伪元素。我不知道渲染速度。它还有一个缺点,即它不适用于 IE8,因为您不能应用于filterpseudo-elements。但是,由于您将这个想法与 CSS3 透视等结合使用,因此 IE8 警告对您来说不是问题。

这实现了从阴影中抽象出纹理。:after它甚至可以通过伪元素添加另一层,如果需要/需要,它仍然可以在三个中的每一个中使用多个背景。

这是小提琴。

示例代码:

HTML

<div class="texture"></div>
<div class="texture light"></div>
<div class="texture medium"></div>
<div class="texture dark"></div>

CSS(核心)

.texture {
    position: relative;
    background: url(http://www.dummyimage.com/12x16/ff0000/ffffff.png&text=X++) top left repeat;
}

.light:before,
.medium:before,
.dark:before {
    content: '';
    position: absolute;
    top:0;
    right: 0;
    bottom:0;
    left: 0;
}
.light:before {
    background: -moz-linear-gradient(left,  rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.1) 100%);
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.3)), color-stop(100%,rgba(0,0,0,0.1)));
    background: -webkit-linear-gradient(left,  rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
    background: -o-linear-gradient(left,  rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
    background: -ms-linear-gradient(left,  rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
    background: linear-gradient(to right,  rgba(0,0,0,0.3) 0%,rgba(0,0,0,0.1) 100%);
}
.medium:before {
    background: -moz-linear-gradient(left,  rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.2) 100%);
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.6)), color-stop(100%,rgba(0,0,0,0.2)));
    background: -webkit-linear-gradient(left,  rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
    background: -o-linear-gradient(left,  rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
    background: -ms-linear-gradient(left,  rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
    background: linear-gradient(to right,  rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.2) 100%);
}
.dark:before {
    background: -moz-linear-gradient(left,  rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.3) 100%);
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0.8)), color-stop(100%,rgba(0,0,0,0.3)));
    background: -webkit-linear-gradient(left,  rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
    background: -o-linear-gradient(left,  rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
    background: -ms-linear-gradient(left,  rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
    background: linear-gradient(to right,  rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.3) 100%);
}
于 2013-01-21T15:13:41.507 回答