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

时间:2014-06-12 21:48:09

标签: javascript jquery html css background

主要解决方案是:

  

"只需加载一个加载屏幕,直到页面加载为#34;。

但我的目标是构建能够非常快速地显示基础知识的页面,而无需加载屏幕,然后在图像和花哨功能准备好后进行转换。因此,我会等到它被加载,然后将其淡入。或者我将以非常低的版本加载,然后在准备就绪时淡入高分辨率。 / p>

我还没想到的这种做法的一个方面是如何用背景图像来做。

如何使用背景图像实现平滑淡入效果?

我愿意使用:

  • 的Javascript
  • JQuery的
  • 任何现代JQuery库
  • CSS技巧/" hacks"

但我想避免:

  • 使用叠加元素并将其淡入顶部。

3 个答案:

答案 0 :(得分:7)

如@dandavis的评论所述,实际上有一个CSS过渡属性:background-image。

解决方案,利用CSS背景转换属性:

  1. 创建两个相同大小的背景图片:一个透明&一个有意的。 (如果你没有使它们大小相同,you'll get this effect!);

  2. 使用transition: background-image 1s来产生过渡效果

  3. 使用Javascript预加载图像并在准备好后重置背景图像。 CSS将负责其余部分。

  4. 值得注意的限制


    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>

答案 1 :(得分:6)

我想我有一个解决方案! (对不起,我刚刚退出了这个工作:)

//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

我基本上最终建立了一个小型图书馆。纯JavaScript,不需要jQuery。


您只需在 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
};

并将以下内容添加到 CSS

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

因此,对于具有背景图像的每个元素,您必须添加#example::after {规则并将背景图像放在那里。 (您不必在HTML中执行此操作,仅在CSS中执行此操作。)


我已将库的源代码添加为下面的代码段。评论在代码中 您可以将代码粘贴到自己脚本的顶部,也可以将代码放在文件和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 (e.g. the first '<style></style>').
     * A filename is for external sheets (e.g. '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!
(库的源代码,而不是工作代码段)

有趣的事实:这不适用于jsfiddle.net,因为他们自己的样式表与小提琴中的样式表混在一起,因此无法确定所需的CSS规则(基于数字)驻留。

答案 2 :(得分:2)

不清楚你是否已经解决了这个问题:对于常规的<img>图像,将另一个<img>置于其上方(显示:inline-block; visibility:hidden;)并监听高分辨率的onload图像将起作用:

$("high-res").load(function() {
    $(this).css({visibility: "hidden", opacity: 0}).fadeIn("slow");
}
编辑:反之亦然(将高分辨率放在低分辨率后面,然后逐渐淡出低分辨率)也有效。但你不会绕过覆盖的东西。

CSS背景图像的淡入是不可能的。它们没有不透明度值。您唯一能做的就是将内容放在<div> <img>上方,并以同样的方式淡化。