今天在爆栈上刷信仰积分时看到这样一道问题

How to animate the height of the background image

I have tried the following scenario which I need to animate my background image like filling from bottom to top on hover of my div. Whereas my animation is not like filling from bottom instead its like sliding from bottom to top. Can any one suggest me the right way how I can achieve my result. I am ok with jQuery animation as well and css3 keyframe animation.

Code:

<div class="bg"><span></span></div>  
.bg {
  background: url(...) no-repeat center;
  height: 250px;
  position: relative;
}
span {  
  background: url(...) no-repeat top 32px center;
  bottom: 0px;
  height: 0;
  transition: height 0.5s;
  position: absolute;
  right: 0;
  left: 0;
}
.bg:hover span {
  height: 184px;
}

大意是要实现一个背景图片自下而上展开的效果,如图:

Round #1

「固定背景位置和大小不就好了嘛!」刚看到这个问题时,我不加思索就这样判定了。很快,第一版代码就出来了:

span {  
  background: url(...) no-repeat center 106px;

  background-attachment: fixed; /* set background to be fixed */
  background-size: 282px 152px; /* specify image size */
}

.bg:hover span {
  height: 152px;
}

拿 chrome 开发工具一点一点矫正完背景位置,一看效果简直完美,于是就愉快地提交了答案:

background-attachment: fixed will be helpful

正当我还在洋洋自得时,突然想到 background-attachment: fixed 是针对视口固定位置的 [1]!也就是说,我只要滚动页面,叠加背景的位置就不会和主背景重叠了:

果然,刚回到爆栈就收到回复:

Thats was real clever answer but when I scroll because of the fixed position my content is sticked with the same position. – Benjamin

好累。

Round #2

我错了我去掉 background-attachment: fixed 好了吧……很快,第二版出炉了:

span {  
  background: url(...) no-repeat center bottom;
  background-size: 282px 152px; /* specify image size */
}

测试,Nice!什么问题都没有了!于是愉快地更新了答案:

specify the size of background image will be helpful

果不其然,数分钟后收到了回复:

You are a life saver thats really what i wanted i owe you. – Benjamin

「哈哈哈!聪明机智如我,分分钟解决问题!」正当我看着今天 get 到的一百点爆栈信仰积分,思考要不要把简介改成 The magician of css. 时,再次被啪啪啪打脸了:

Its not about the background-image-size is all about the background-image-position: center bottom that make the difference. – Benjamin

WTF!

不指定 background-size 的时候默认 auto 不就为图片大小了为什么还要去手动指定尺寸为图片大小麻烦死了你个大傻X!

Round #3

备受打击的我不得不去把代码改成这样:

span {  
  background: url(...) no-repeat;
  background-position: center bottom;
}

然后附上一句

Seeming I had scored a lucky hit XD

题主愉快地回了一句

Yep this is your lucky day.

让我一个人静一静……

解析

那么为什么设定 background-position: bottom 就能达到效果呢?我们先看看 bottom 这个值是怎么定义的:

bottom: Computes to ‘100%’ for the vertical position if one or two values are given, otherwise specifies the bottom edge as the origin for the next offset.

哦..也就是一个 background-position-y: 100% 的效果了。

而对 background-position 赋百分比值时,它的定位过程如下[2](以 background-position: 75% 50% 为例):

  1. 计算得到元素位于 left: 75%; top: 50% 的坐标点 A
  2. 计算背景图片位于 left: 75%; top: 50% 的坐标点 B
  3. 使 A, B 两点 重合,绘制背景图片

整个过程如图所示:

所以,当我们指定背景位置 background-position: center bottom 时,实际指定了 background-position-x: 50%; background-position-y: 100%。这样一来,背景图片的底边缘始终要和元素的底边缘重合,当元素高度变化时,在视觉上背景图片就好像是从底部「长」出来一样:

(全文完)

参考

  1. background-attachment | MDN
  2. CSS Backgrounds and Borders Module Level 3