10

I have an image in <img> tag. My aim is to create a reflection of that image using only CSS. It also has to be compatible with all browsers. I tried various ways to do it one of them is in this JS Fiddle

What I want:
The Fade to Zero opacity from top to bottom on the reflection. Right now it works only in webkit browsers using combination of -webkit-box-reflect and -webkit-gradient.
I want it to work on Mozilla too.

What I have right now:
As it can be seen in the JSfiddle I got it working in the webkit browsers using:

-webkit-box-reflect: below 0px 
-webkit-gradient(linear, left top, left bottombottom, from(transparent), color-stop(70%, transparent) , to(rgba(250, 250, 250, 0.1)));

I tried the following for Mozilla:

#moz-reflect:after {  
    content: "";  
    display: block;  
    background: -moz-element(#moz-reflect) no-repeat;  
    width: auto;  
    height: 200px;  
    margin-bottom: 100px;  
    -moz-transform: scaleY(-1);  
}

where #moz-reflect is the container div for the <img>.

I'd appreciate answers which can solve the problem with CSS only. There are a lot of images (Icons) to which this effect has to be applied.

If there is no way it can be made to work in Mozilla using just CSS then I wouldn't mind going down the JavaScript road.

Update It has to work on custom background which may be an image or black or any other color.

md1hunox
  • 3,815
  • 10
  • 45
  • 67

2 Answers2

11

I've changed your code totally, I am using CSS3 gradients with transform property, this is Pure CSS with maximum compatibility.

Here, the key thing I am using is rgba() along with the transform property applied to second img which am targeting using nth-of-type pseudo.

Also, make sure that you have called position: relative; on the parent element because I am using :after pseudo for the gradient overlay from the bottom, so am using position: absolute; for that with the bottom set to 0

Demo (Had made a bit mistake here by using rotate() as it won't give reflection effect, will just rotate the image infact, please refer to my second demonstration)

Demo 2 (Using scale for mirroring images, can use rotateY as well, as pointed out in the comments..)

#moz-reflect:after {
    content:"";
    width: 100%;
    height: 200px;
    position: absolute;
    bottom: 0;
    left: 0;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.67) 49%, rgba(255, 255, 255, 1) 100%);
    /*I've removed proprietary gradient codes from here, you can get it in the demo*/
}

#moz-reflect img:nth-of-type(2) {
    -webkit-transform: scaleY(-1);
       -moz-transform: scaleY(-1);
        -ms-transform: scaleY(-1);
         -o-transform: scaleY(-1);
            transform: scaleY(-1); 
}

#moz-reflect {
    position: relative;
}

Demo 3 (Only difference is, that am using height: 50%; for the :after pseudo so we don't have to hard code it)

Only code to modify in the above block of code is the height property which am setting to 50%

#moz-reflect:after {
    content:"";
    width: 100%;
    height: 50%; /* Changed the unit over here */
    position: absolute;
    bottom: 0;
    left: 0;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.67) 49%, rgba(255, 255, 255, 1) 100%);
}

Note: Inorder to create the gradients best suited, say black opaque gradients will be required for websites with black background, than you can make your own using Color Zilla.

Image reflection, using black as the body background. Only changes in the above snippet of code is that am applying background: #000; to body and I've tweaked the gradient accordingly.

background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.67) 49%, rgba(0, 0, 0, 1) 100%);

Demo (For websites using darker backgrounds, black in this case)

Note: Didn't added proprietary properties for gradient in the black demo

Mr. Alien
  • 153,751
  • 34
  • 298
  • 278
  • 1
    To get the desire effect I suggest use `scaleY` instead of `rotate` Check this http://jsfiddle.net/FWB7K/7/. With rotate seems not fine the effect – DaniP Feb 07 '14 at 19:33
  • Thanks for the answer. Albeit what you did there will work when there is white background alright, but with custom background it wouldn't look great. I have just updated my question. I forgot to include that part earlier. – md1hunox Feb 07 '14 at 19:34
  • @Danko was editing the answer only, cuz I realized when I was watching the demo, I made this on an image where it wasn't y axis conscious, refreshed 2 to 3 times but didn't striked that the thing was wrong at first place :) though thanks for the comment... – Mr. Alien Feb 07 '14 at 19:34
  • @FillipPeyton yes we can, I was bit excited while posting, so fixed the codes now, thanks for the inputs.. appreciated... – Mr. Alien Feb 07 '14 at 19:36
  • @vineetrok well, that's all from me, if you add the conditions lately I cannot help it :) and you welcome.. you can wait for another solutions if this didn't sufficed.. – Mr. Alien Feb 07 '14 at 19:37
  • @Mr.Alien Yep, my bad! Your answer will suffice for now. If my updated condition is satisfied it'll be a bonus. So, i'll wait for other answers if they are coming. – md1hunox Feb 07 '14 at 19:44
  • 2
    @Charles380 if you have another solution post it - editing content in answers (aside from grammar, broken links, etc) is bad mojo. – rlemon Feb 07 '14 at 20:00
0

You can also use a single image element along with ::before and ::after, however it's not very useful (yet), since you have to hard-code a background-image:url() for the ::before pseudo-element. I'm posting this answer because someone else may want to do it this way, and hopefully one day we'll be able to use background-image: attr(src, url); syntax. (1) As of June 2014, no browsers support this.

A fiddle: http://jsfiddle.net/DeedH/5/

I'm assuming you have a black background.

Structure:

  1. img - main image (actually displayed as a background-image),
  2. ::before containing the reflection. Must be display:inline-block in order to use the transform:scaleY to flip the image.
  3. ::after containing a gradient mask.

The html: (note that currently the src is not used).

<img class="reflect" src="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSYXWxD2yC7m2m1ZylyVq_r6yWE4ewJv64cmt3CpgbGdqZq3wEx" />

The CSS:

.reflect {
    position:relative;
    display:block;
    height:300px;
    width:300px;
    background-image:url('https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSYXWxD2yC7m2m1ZylyVq_r6yWE4ewJv64cmt3CpgbGdqZq3wEx');
    background-repeat:no-repeat;
    background-size:contain;
    content:'';
}
.reflect::before {
    position:relative;
    top:20%;
    height:100%;
    width:100%;
    display: inline-block;
    -moz-transform: scaleY(-.7);
    -o-transform: scaleY(-.7);
    -webkit-transform: scaleY(-.7);
    transform:scaleY(-.7);
    opacity:0.2;
    background-image:url('https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSYXWxD2yC7m2m1ZylyVq_r6yWE4ewJv64cmt3CpgbGdqZq3wEx');
    background-repeat:no-repeat;
    background-size:contain;
    content:'';
}
.reflect::after {
    position:relative;
    top:-40%;
    height:70%;
    width:100%;
    background-image:-webkit-radial-gradient(top center, 50% 75%, rgba(0,0,0,0), rgba(0,0,0,1));
    background-image:-moz-radial-gradient(top center, 50% 75%, rgba(0,0,0,0), rgba(0,0,0,1));
    background-image:-o-radial-gradient(top center, 50% 75%, rgba(0,0,0,0), rgba(0,0,0,1));
    background-image:radial-gradient(top center, 50% 75%, rgba(0,0,0,0), rgba(0,0,0,1));
    background-repeat:no-repeat;
    background-size:contain;
    content:'';
}

Note that you must use content:''; on the img itself, otherwise the pseudo-elements won't display.

Also be aware that this is not really applicable to a class of images because you have to hard-code the image url. But this could be useful if you used it by id and used js to write the rules to a document level stylesheet. Otherwise, this is only helpful for single images.

(1). Using HTML data-attribute to set CSS background-image url

Community
  • 1
  • 1
Josiah
  • 3,008
  • 1
  • 34
  • 45