简体   繁体   English

如何平滑过渡CSS背景图像?

[英]How can I smoothly transition CSS background images?

The main solution out there is: 那里的主要解决方案是:

"Just throw a loading screen up until the page is loaded". “只需加载一个加载屏幕,直到加载页面”。

But my goal is to build pages that present the basics very quickly, without a loading screen, and then transition in the images and fancy features when they're ready. 但我的目标是构建能够非常快速地显示基础知识的页面,而无需加载屏幕,然后在图像和花哨功能准备好后进行转换。 So I'll wait till it's loaded, and then fade it in. Or I'll load in a very low res version and then fade in the high res when it's ready. 所以我会等到它被加载,然后淡入它。或者我将加载一个非常低分辨率的版本,然后在它准备好时淡入高分辨率。

The one aspect of this practice that I have not yet figured out is how to do it with background images. 我还没想到的这种做法的一个方面是如何用背景图像来做。

How can I achieve the affect of a smooth fade in with background images? 如何通过背景图像实现平滑淡入的效果?

I'm willing to use: 我愿意用:

  • Javascript 使用Javascript
  • JQuery JQuery的
  • Any modern JQuery library 任何现代的JQuery库
  • CSS tricks / "hacks" CSS技巧/“黑客”

But I want to avoid: 但我想避免:

  • Using an overlay element and fading that in on top. 使用覆盖元素并在顶部淡化。

As noted in the comments by @dandavis, there's actually a CSS transition property : background-image. 正如@dandavis的评论中所指出的,实际上有一个CSS过渡属性:background-image。

The solution, utilizing the CSS background transition property: 解决方案,利用CSS背景过渡属性:

  1. create two background images of the same size : one transparent & one that's intended. 创建两个相同大小的背景图像:一个透明,一个是预期的。 (If you don't make them the same size, you'll get this effect! ); (如果你没有使它们大小相同, 你会得到这种效果! );

  2. use transition: background-image 1s to cause the transition effect 使用transition: background-image 1s来产生过渡效果

  3. use Javascript to preload the image and reset the background image when it's ready. 使用Javascript预加载图像并在准备好后重置背景图像。 CSS will take care of the rest. CSS将负责其余部分。

Notable Limitations 显着的局限性


Working Example 工作实例

 var image = new Image(); image.onload = function () { $(".element").css("background-image", "url('" + image.src + "')"); } image.src = "https://c1.staticflickr.com/3/2439/3728897793_ff1c78c5d9.jpg"; //image to be transitioned to 
 html{ width:100%; height:100%; } body{ width:100%; height:100%; padding:0px; margin:0px; } .element{ width:100%; height:100%; background-image:url('http://i.imgur.com/HRV3DsM.jpg'); -webkit-transition: background-image 5s; } 
 <div class="element"> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> 

I think I have a solution! 我想我有一个解决方案! (sorry, just very exited I got this working:) (对不起,刚刚离开我得到了这个工作:)

 //library (minified) this.BgImgFader=function(){var styleRules;function getArray(str){if(str.indexOf(',')==0){str.substring(1);}if(str.lastIndexOf(',')==str.length-1){str.substring(0,str.length-1);}if(str.indexOf(',')==-1){var selectors=[str];}else{var selectors=str.split(',');}for(var i=0;i<selectors.length;i++){selectors[i]=selectors[i].trim();}return selectors;}function getStyleSheet(style){if(typeof style==='number'){return document.styleSheets[style];}else{for(var i=0;i<document.styleSheets.length;i++){var file=document.styleSheets[i].href;file=file.substring(file.lastIndexOf('/')+1);if(file.toLowerCase()==style.toLowerCase()){return document.styleSheets[i];}}}}function addStyleRule(sheet,selector,declarations){if(sheet.addRule){sheet.addRule(selector,declarations);}else{sheet.insertRule(selector+'{'+declarations+'}');}}this.prepare=function(style,selectors){var selectors=getArray(selectors);var styleSheet=getStyleSheet(style);for(var i=0;i<selectors.length;i++){addStyleRule(styleSheet,selectors[i],'position:relative;');addStyleRule(styleSheet,selectors[i]+'::after','position:absolute;top:0;right:0;bottom:0;left:0;opacity:0.0;content:"";');}};this.fade=function(style,selectors,global,opacity,endOpacity,delta){var selectors=getArray(selectors);var styleSheet=getStyleSheet(style);styleRules=styleSheet.rules?styleSheet.rules:styleSheet.cssRules;fadeOpacity(selectors,global,opacity,endOpacity,delta,[]);};function fadeOpacity(selectors,global,opacity,endOpacity,delta,rules){opacity+=delta;if(rules.length==0){for(var i=0;i<selectors.length;i++){for(var j=0;j<styleRules.length;j++){if(global&&styleRules[j].selectorText.toLowerCase().indexOf(selectors[i].toLowerCase()+'::after')!=-1){rules.push(styleRules[j]);}else if(styleRules[j].selectorText.toLowerCase()==selectors[i].toLowerCase()+'::after'){rules.push(styleRules[j]);break;}}}}for(var i=0;i<rules.length;i++){rules[i].style.opacity=opacity;}if(opacity<endOpacity){setTimeout(function(){fadeOpacity(selectors,global,opacity,endOpacity,delta,rules);},0);}else{for(var i=0;i<rules.length;i++){rules[i].style.opacity=endOpacity;}rules.length=0;}}}; //instantiate BgImgFader in global domain var BgImgFader = new BgImgFader(); window.onload = function(){ //prepare specified elements BgImgFader.prepare(0, '.exampleClass'); //style, selectors //fade specified elements BgImgFader.fade(0, '.exampleClass', true, 0, 0.5, 0.002); //style, selectors, global, startOpacity, endOpacity, delta }; 
 #exampleId { width: 300px; height: 200px; margin: 10px 0px 0px 10px; background-color: #AAAAAA; } #exampleId .exampleClass { width: 200px; height: 130px; padding: 5px; } #exampleId .exampleClass::after {background:url(https://placeimg.com/640/480/any) center/cover no-repeat;} 
 <div id="exampleId"> Some other text to illustrate how this can be implemented. <div class="exampleClass"> I assume you want transparent background images because you have text in the element that you do want to show from the start? </div> </div> 
codepen: https://codepen.io/anon/pen/QMLPbr codepen: https ://codepen.io/anon/pen/QMLPbr

I basically ended up building a tiny library. 我基本上最终建立了一个小型图书馆。 Pure JavaScript, no jQuery required. 纯JavaScript,不需要jQuery。


All you have to do is add these three BgImgFader lines in JS : 你要做的就是在JS中添加这三个BgImgFader行:

 //instantiate BgImgFader in global domain var BgImgFader = new BgImgFader(); window.onload = function(){ //prepare specified elements BgImgFader.prepare(0, '.exampleClass'); //stylesheet, selectors //fade specified elements BgImgFader.fade(0, '.exampleClass', true, 0, 0.5, 0.002); //stylesheet, selectors, global, startOpacity, endOpacity, delta }; 

And add the following to all your background-image-elements in CSS : 并将以下内容添加到CSS中的所有background-image-elements:

 #example {...} #example::after {background:url(path/to/image.png) center/cover no-repeat;} 

So for every element with a background-image, you have to add the #example::after { rule and place your background-image in there. 因此,对于具有背景图像的每个元素,您必须#example::after { rule并将背景图像放在那里#example::after {添加#example::after { (You do NOT have to do this in HTML, only in CSS.) (您不必在HTML中执行此操作,仅在CSS中执行此操作。)


I've added the library's source code as a code snippet below. 我已经将库的源代码添加为下面的代码片段。 Comments are in the code. 评论在代码中。
You can either paste the code at the top of your own script, or put the code in a file and in your HTML, link to that file like you would to any other library (before your own code): 您可以将代码粘贴到自己脚本的顶部,也可以将代码放在文件和HTML中,链接到该文件,就像您对任何其他库一样(在您自己的代码之前):

 <script type="text/javascript" src="path/to/bgimgfader.js"></script> 

 /** * BgImgFader - Library: * This library makes it possible to fade the background-image of an element. * The image can be faded in or out. * * Compatibility: * - IE9 and higher should be fine, lower could give trouble. * - Older versions of FF/Chrome will probably give some problems too, but I think we can safely assume * that those who chose either one of these browsers, did so because they choose NOT to live in the past.. * - Opera and others... I have absolutely no idea. * * ################################################################################# * INSTRUCTIONS--------------------------------------------------------------------- * 1. In CSS: * a. For every element with a background-image, create an '::after' rule, and put the image in there: * (You don't have to create these '::after'-elements in the HTML) * * #element {...} * #element::after {background:url(path/to/image.png) center/cover no-repeat;} * * The following declarations will be added by the BgImgFader, keep that in mind: * #element {position:relative;} * #element::after {position:absolute; top:0;right:0;bottom:0;left:0; opacity:0.0; content:"";} * * (The important one is 'position:relative;', the ones on the '::after'-element have no consequences) * * --------------------------------------------------------------------------------- * 2. In JavaScript: * a. Instantiate the BgImgFader in the global domain: var BgImgFader = new BgImgFader(); * * * b. Prepare the elements with a background-image: BgImgFader.prepare(0, 'elements'); //style, selectors * * - style: Reference to the style sheet with the rules for the specified elements. * This can be either an INTEGER for internal style sheets (0), * or a STRING of a filename for external style sheets ('style.css'). * - selectors: STRING reference to the selectors in the style rules. * This works the same as in the CSS, below a few examples. * Individual tags: ('div') ('#id') ('.class') * Multiple tags: ('div.class') ('#id .class') ('.class.subclass') * Multiple selectors: ('div, #id, div.class, #id .class, .class.subclass') * * * c. Initiate the fade: BgImgFader.fade('style.css', 'elements', true, 0, 0.5, 0.005); //style, selectors, global, startOpacity, endOpacity, delta * * - style: See 2b for the details. * - selectors: See 2b for the details. * - global: BOOLEAN that deternimes whether only complete matches for the selectors are allowed, * or partial matches as well, increasing the range of the BgImgFader. * TRUE allowes partial matches: feed the BgImgFader '.class' and it will also try to fade 'div .class'. * FALSE allowes only complete matches. * - startOpacity: FLOAT that indicates the start opacity (0.0 - 1.0). * - endOpacity: FLOAT that indicates the end opacity (0.0 - 1.0). * - delta: FLOAT that indicates the delta of every fade-iteration (1.0 - 0.00000000...1). * The effective range is approximately (0.1 - 0.0001). * A smaller delta means a slower fade. * A positive delta in combination with start<end fades the image in. * A negative delta in combination with start>end fades the image out. * * ################################################################################# */ this.BgImgFader = function() { var styleRules; //GET/SET-FUNCTIONS================================================================= //GET SELECTORS--------------------------------------------------------------------- function getArray(str) { /* This function is invoked by this.prepare() and this.fade(). * This function converts the specified string of selectors to an array, and returns that. */ //strip trailing comma's if (str.indexOf(',')==0) {str.substring(1);} //strip first comma if (str.lastIndexOf(',')==str.length-1) {str.substring(0,str.length-1);} //strip last comma //store selectors in array if (str.indexOf(',')==-1) {var selectors = [str];} else {var selectors = str.split(',');} //trim trailing spaces for (var i=0; i<selectors.length; i++) { selectors[i] = selectors[i].trim(); } return selectors; } //GET STYLE SHEET------------------------------------------------------------------- function getStyleSheet(style) { /* This function is invoked by this.prepare() and this.fade(). * This function returns a reference to the specified style sheet, * based on either a number or a filename of the sheet. * A number is for internal sheets, where the number stands * for its location in the HTML (eg the first '<style></style>'). * A filename is for external sheets (eg 'style.css'). * See the instructions in the header of this file for details. */ if (typeof style === 'number') { return document.styleSheets[style]; } else { //find style sheet for (var i=0; i<document.styleSheets.length; i++) { var file = document.styleSheets[i].href; file = file.substring(file.lastIndexOf('/')+1); if (file.toLowerCase() == style.toLowerCase()) { return document.styleSheets[i]; } } } } //SET STYLE RULE-------------------------------------------------------------------- function addStyleRule(sheet, selector, declarations) { /* This function is invoked by this.prepare(). * This function dynamically adds the specified rule to the specified style sheet. */ if (sheet.addRule) {sheet.addRule(selector,declarations);} //IE... else {sheet.insertRule(selector+'{'+declarations+'}');} //NON-IE... } //PREPARE=========================================================================== this.prepare = function(style, selectors) { /* This function is invoked by an external function, outside of the library. * This function is an interface for external scripts to access this library. * The function prepares the elements specified by the selectors, by adding certain style rules * to them that are necessary for this library to successfully manipulate the background-image. */ var selectors = getArray(selectors); var styleSheet = getStyleSheet(style); for (var i=0; i<selectors.length; i++) { addStyleRule(styleSheet,selectors[i],'position:relative;'); addStyleRule(styleSheet,selectors[i]+'::after','position:absolute; top:0;right:0;bottom:0;left:0; opacity:0.0; content:"";'); } }; //FADE BACKGROUND IMAGE============================================================= //INIT------------------------------------------------------------------------------ this.fade = function(style, selectors, global, opacity, endOpacity, delta) { /* This function is invoked by an external function, outside of the library. * This function is an interface for external scripts to access this library. * The function initiates the fading process. It first stores the appropriate * set of style rules into the style rules variable, and then invokes * fadeOpacity() to start the fading. */ var selectors = getArray(selectors); var styleSheet = getStyleSheet(style); styleRules = styleSheet.rules ? styleSheet.rules : styleSheet.cssRules; //IE uses 'rules', NON-IE use 'cssRules' fadeOpacity(selectors,global,opacity,endOpacity,delta,[]); }; //FADE------------------------------------------------------------------------------ function fadeOpacity(selectors, global, opacity, endOpacity, delta, rules) { /* This function is invoked by fade(). * This function fades the background-image of the specified elements, by * adding the delta to the current opacity, and then setting the opacity * of all specified elements to that new value. */ opacity += delta; if (rules.length == 0) { //find the css-rules that match the specified selector(s) for (var i=0; i<selectors.length; i++) { for (var j=0; j<styleRules.length; j++) { if (global && styleRules[j].selectorText.toLowerCase().indexOf(selectors[i].toLowerCase()+'::after')!=-1) { rules.push(styleRules[j]); } else if (styleRules[j].selectorText.toLowerCase() == selectors[i].toLowerCase()+'::after') { rules.push(styleRules[j]); break; } } } } //set the opacity of the background-image for every matched rule for (var i=0; i<rules.length; i++) { rules[i].style.opacity = opacity; } //check if the end-opacity is reached if (opacity < endOpacity) { setTimeout(function(){fadeOpacity(selectors,global,opacity,endOpacity,delta,rules);},0); //invoke itself again } else { //manually set the opacity to the end-opacity (otherwise it'll be off by a fraction) for (var i=0; i<rules.length; i++) { rules[i].style.opacity = endOpacity; } rules.length = 0; } } }; 
 source code of library, not a working code snippet! 
(source code of library, not a working code snippet) (库的源代码,不是工作代码片段)

Interesting fact: This does not work on jsfiddle.net , because their own style sheets get mixed in with the one from the fiddle, making it impossible to determine in which sheet (based on number) the required CSS-rules reside. 有趣的事实:这在jsfiddle.net不起作用 ,因为它们自己的样式表与小提琴中的样式表混合在一起,使得无法确定所需的CSS规则所在的表(基于数字)。

Not clear if you solved that already: For regular <img> images putting another <img> above it (display: inline-block; visibility: hidden;) and listening to the onload of the high-res image will work: 不清楚你是否已经解决了这个问题:对于常规<img>图像,将另一个<img>置于其上方(显示:内联块;可见性:隐藏;)并且监听高分辨率图像的onload将起作用:

$("high-res").load(function() {
    $(this).css({visibility: "hidden", opacity: 0}).fadeIn("slow");
}

EDIT: The other way around (putting the high-res behind the low-res and then fading out the low-res) also works. 编辑:反过来(将高分辨率放在低分辨率后,然后淡出低分辨率)也有效。 But you wont get around overlaying stuff. 但你不会绕过覆盖的东西。

Fading in CSS background-images is impossible. CSS背景图像的淡入是不可能的。 They have no opacity value. 它们没有不透明度值。 The only thing you can do is put the contents in a <div> above an <img> and fading that in the same way. 你唯一能做的就是将内容放在<img>上方的<img> <div> ,并以同样的方式淡化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM