How to simply create an image reflection effect in JavaScript/CSS? - css

I have spent some time to look up how to best create a dynamic image reflection effect.
Options I found were:
non-standard browser tags such as -webkit-reflect,
adding libraries from <2012 that all have outdated dependencies and fail when combining with e.g. up to date JQuery 3, or
dropping the idea of dynamic image reflections and relying on GIMP/Photoshop.
Also most existing solutions fail on non plain background, i.e. textures.
The drawbacks of the above lie at hand. Unfortunately I do not have a web blog where to post what I came up with, yet I think it would be worth sharing (see self-answer below).

Add an image to your HTML:
<img class="reflect" src="some/image.png" />
Add the following CSS rules:
img.reflect {
width: calc(100% - 20px); /* not sure how else to allow for margin */
margin-left: 10px;
}
img.reflection {
position: absolute;
opacity: 0.4;
margin-top: 4px;
width: calc(100% - 20px);
-webkit-mask-image: -webkit-linear-gradient(transparent 75%, black 100%);
mask-image: linear-gradient(transparent 75%, black 100%);
-webkit-transform: translateX(calc(-100% - 10px)) translateY(100%) scaleY(-1) ;
transform: translateX(calc(-100% - 10px)) translateY(100%) scaleY(-1);
}
If you don't want to rely on any JavaScript you could now simply add the reflection by inserting the reflection tag right after the image tag from (1):
<img class="reflection" src="some/image.png" />
Otherwise
For example, extend JQuery with the following function:
$.fn.reflect = function() {
var reflection = this.clone();
this.after(reflection);
reflection.addClass("reflection");
};
Then reflect the image:
$(".reflect").reflect();

Here is a pure CSS solution without the need of jQuery or JS:
.reflect {
display:inline-block;
vertical-align:top;
width:150px;
height:300px;
background:
linear-gradient(#000,#000) center/100% 1px no-repeat, /*a separation*/
var(--img) top/100% 50% no-repeat;
position:relative;
}
.reflect::before {
content:"";
position:absolute;
bottom:0;
left:0;
right:0;
top:0;
background:inherit;
transform:scale(1,-1);
-webkit-mask-image: -webkit-linear-gradient(transparent 25%, #ccc 50%);
mask-image: linear-gradient(transparent 25%, #ccc 50%)
}
.right {
width:300px;
height:150px;
background-position:center,left;
background-size:1px 100%,50% 100%;
}
.right:before {
transform:scale(-1,1);
-webkit-mask-image: -webkit-linear-gradient(left,transparent 25%, #ccc 50%);
mask-image: linear-gradient(to left,transparent 25%, #ccc 50%)
}
<div class="reflect" style="--img:url(https://picsum.photos/200/200?image=0)"></div>
<div class="reflect right" style="--img:url(https://picsum.photos/200/200?image=1069)"></div>

Related

calculated gradient in html2canvas doesn't work properly

I am trying to take a screenshot of a page that has images overlayed by linear-gradient with the help of html2canvas. The height of the image varies but the width is fixed to 210px so, i need to use calc to calculate the positons of the gradient, which is not rendering in the way it looks on the screen.
Example with static values: https://jsfiddle.net/vpj3bz7s/1/
.linearGradient {
height: 200px;
width: 210px;
background-image: linear-gradient(to top left,
yellow 0%,
yellow 80px,
red 80px,
red 110px,
yellow 110px,
yellow 100%);
}
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
}
);
<div class="linearGradient"></div>
Example with calc values: https://jsfiddle.net/dk309pf6/2/
.linearGradient {
height: 200px;
width: 210px;
background-image: linear-gradient(to top left,
yellow 0%,
yellow calc(50% - 10px),
red calc(50% - 10px),
red calc(50% + 10px),
yellow calc(50% + 10px),
yellow 100%);
}
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
}
);
<div class="linearGradient"></div>
Edit:
Actual image overlayed on gradient looks like this:
The way it looks like in a screenshot is this:
The JS fiddle with my actual code is as follows (But the screenshot is a little different from my original one)
https://jsfiddle.net/nrfjh8m3/1/
Here is a different idea to obtain the same gradient. There is a ton of ways but the below is the only one that worked with html2canvas:
body {
margin: 0px;
}
.linearGradient {
height: 200px;
width: 210px;
background-color:red;
overflow:hidden;
position:relative;
}
.linearGradient::before,
.linearGradient::after {
content:"";
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
background-repeat:no-repeat;
}
.linearGradient::before {
background:linear-gradient(to bottom right,yellow 49%, transparent 50%);
bottom:10px;
right:10px;
}
.linearGradient::after {
background:linear-gradient(to top left,yellow 49%, transparent 50%);
top:10px;
left:10px;
}
<div class="linearGradient"></div>
Working code with html2canvas:
https://jsfiddle.net/k79ybnup/1/

White CSS arrow inside div

I'm looking to create this white arrow that goes inside the image with the HTML you can find in the snippet in a pure CSS way, not editing any HTML code.
.foto {
width: 100%;
float: left;
min-height: 215px;
background:
linear-gradient(to bottom right,transparent 50%,#fff 0) bottom right/10% 50% no-repeat, linear-gradient(to bottom left,#fff 50%,transparent 0%) top right/10% 50% no-repeat, url(https://s3.pagegear.co/1/contents/blog/2016/imagen_cachorro_comprimir.jpg) center/cover
}
<div class="foto bg_fix"><img src="https://s3.pagegear.co/1/contents/blog/2016/imagen_cachorro_comprimir.jpg" itemprop="image" width="724" height="230" style="display: none;"></div>
If you do not need to support Edge, you can get away with the clip-path. It's by far the easiest solution to your problem.
You can check the support on CanIUse
Also, amazingly helpful tool for this is Clippy, but don't forget to read about this technique on MDN - CSS clip-path.
.foto {
width: 100%;
float: left;
min-height: 215px;
-webkit-clip-path: polygon(100% 0%, 85% 50%, 100% 100%, 0 100%, 0% 50%, 0 0);
clip-path: polygon(100% 0%, 85% 50%, 100% 100%, 0 100%, 0% 50%, 0 0);
}
/* first value is X, and second value is Y coordinate. Feel free to experiment with percentages according to your needs. */
SOLUTION 2:
Old "trick" which has much much better support => CSS shapes.
You would basically need to create a new element (which is going to be your white triangle) and then put it on top of that image. Here's a sample code for a triangle that you need:
#triangle-left {
width: 0;
height: 0;
border-top: 50px solid transparent;
border-right: 100px solid red; /* red is just for display puproses */
border-bottom: 50px solid transparent;
}
<div id="triangle-left"><div>
Btw, you have both background-image and img tag in your html. Decide which one you want to use, and if you have problem with cropping the image, you may want to look into background position and/or object-fit.
You can correct you gradient like below. You were almost good, simply switch the position of both making the bottom one on the top and the top on on the bottom:
.foto {
min-height: 200px;
background:
linear-gradient(to bottom right,transparent 49.8%,#fff 50%) top right/10% 50%,
linear-gradient(to top right,transparent 49.8%,#fff 50%) bottom right/10% 50%,
url("https://s3.pagegear.co/1/contents/blog/2016/imagen_cachorro_comprimir.jpg") center/cover;
background-repeat:no-repeat;
}
<div class="foto bg_fix" ></div>

Create arrowed background with CSS using repeating-gradient and blend-mode

I thought about creating a background with arrows. Something that looks like in this codepen: http://codepen.io/DaSch/pen/rrWAmy
.top {
height: 5em;
background:
repeating-linear-gradient(
45deg,
lightgray,
lightgray 25%,
gray 0,
gray 50%
);
background-size: 5em 5em;
}
.bottom {
height: 5em;
background:
repeating-linear-gradient(
135deg,
lightgray,
lightgray 25%,
gray 0,
gray 50%
);
background-size: 5em 5em;
}
In the given example there are two elements but together to make it look like I want it to. If I but the gradients together I just get strips. I tried a lot but I can't figure out how to create arrows. with multiple gradients an background-blend-mode.
I'm not sure if this is possible. But I'm looking for a solution without external background-images. If it's not possible a good explanation why would be great.
Here is what I have. It looks like an arrow, and can be repeated using JavaScript. I can't do this with pure CSS. Maybe this solution gives you an idea for your code.
.top {
height: 5em;
width:80px;
margin-left:120px;
background:
repeating-linear-gradient(
45deg,
white,
white 25%,
gray 0,
gray 50%
);
background-size: 5em 5em;
}
.bottom {
height: 5em;
width:80px;
margin-left:120px;
background:
repeating-linear-gradient(
135deg,
white,
white 25%,
gray 0,
gray 50%
);
background-size: 5em 5em;
}
.middle
{
background-color:gray;
height:30px;
width:200px;
margin-right:10px;
}
.maskCornerTop
{
width:40px;
height:40px;
position:relative;
background-color:white;
float:right;
}
.maskCornerBottom
{
width:40px;
height:40px;
background-color:white;
float:right;
margin-top:40px;
position:relative;
}
<div class="top"><div class="maskCornerTop"></div></div>
<div class="middle"></div>
<div class="bottom"><div class="maskCornerBottom"></div></div>
<br/>
<div class="combo"></div>
After some research I found, that the solution is to overlay different backgrounds and use only the half hight for the upper one.
It'll look like this
.combo {
height: 10em;
background:
repeating-linear-gradient(
45deg,
lightgray,
lightgray 33.33%,
gray 33.33%,
gray 66.66%
),
repeating-linear-gradient(
135deg,
gray,
gray 25%,
lightgray 25%,
lightgray 50%
);
background-size: 10em 50%, 10em 100%;
background-repeat: repeat-x, repeat-x;
}
Still this maybe isn't the best solution as it only works if the height of the container is known and fixed.

Can I do a diagonal line in CSS?

I want a design like this:
So in fact a left side with background-color, a right side with background-color (divs of course, easy).
But can I do a diagonal line with CSS?
You can achieve this shape with a skewed pseudo element :
DEMO
HTML :
<div>
<h1>Your title here</h1>
</div>
CSS :
div{
padding:0 10px 10px;
background:#E7E5DD;
}
h1{
margin:0;
display:inline-block;
position:relative;
z-index:1;
padding:10px 50px 10px;
overflow:hidden;
}
h1:before{
content:'';
width:100%; height:100%;
position:absolute;
top:0; left:0;
background:#fff;
z-index:-1;
-webkit-transform: skewX(-20deg);
-ms-transform: skewX(-20deg);
transform: skewX(-20deg);
-webkit-transform-origin:0 0;
-ms-transform-origin:0 0;
transform-origin:0 0;
}
If you want to have with with pure CSS - see
http://css-tricks.com/snippets/css/css-triangle/ and
http://apps.eky.hk/css-triangle-generator/
(You would need a white top-left triangle on the gray area)
width: 0;
height: 0;
border-style: solid;
border-width: 200px 200px 0 0;
border-color: #fff transparent transparent transparent;
Please note that some browsers will not use anti-aliasing when drawing the borders.
A simpler approach in this case would be to have images for background - one for the text with the diagonal line, another one for the grey area.
http://jsfiddle.net/nuxcbqqq/1/
<div class="crossed"></div>
.crossed {
width: 100px;
height: 100px;
background:
linear-gradient(to top left,
rgba(0,0,0,0) 0%,
rgba(0,0,0,0) calc(50% - 0.8px),
rgba(0,0,0,1) 50%,
rgba(0,0,0,0) calc(50% + 0.8px),
rgba(0,0,0,0) 100%),
linear-gradient(to top right,
rgba(0,0,0,0) 0%,
rgba(0,0,0,0) calc(50% - 0.8px),
rgba(0,0,0,1) 50%,
rgba(0,0,0,0) calc(50% + 0.8px),
rgba(0,0,0,0) 100%);
}
Code from here draw diagonal lines in div background with CSS

Making jagged triangle border in CSS

I have a shape with an edge like this in Photoshop:
Is it possible to make the repeated triangles as a border with CSS?
You can use gradients to create a zig-zag patterned background, use the ::after pseud-element to apply it like a border.
.header{
color: white;
background-color: #2B3A48;
text-align: center;
}
.header::after {
content: " ";
display: block;
position: relative;
top: 0px;
left: 0px;
width: 100%;
height: 36px;
background: linear-gradient(#2B3A48 0%, transparent 0%), linear-gradient(135deg, #272220 33.33%, transparent 33.33%) 0 0%, #272220 linear-gradient(45deg, #272220 33.33%, #2B3A48 33.33%) 0 0%;
background-repeat: repeat-x;
background-size: 0px 100%, 9px 27px, 9px 27px;
}
<div class="header"><h1>This is a header</h1></div>
Source: CSS Zigzag Border with a Textured Background
JSFiddle: http://jsfiddle.net/kA4zK/
For future viewers, I found this adaptation of #extramaster's answer to be a little simpler.
It's essentially the same, but it uses one fewer background gradients and allows the backing object (.navbar in my markup) to show through instead of hard-coding the second color into the zig-zag.
JsFiddle: http://jsfiddle.net/861gjx0b/2/
.header {
position: relative;
color: white;
background-color: #2B3A48;
text-align: center;
}
.navbar {
background: #272220;
height: 20px;
}
.header:after {
content: "";
position: absolute;
display: block;
height: 10px;
bottom: -10px;
/* -height */
left: 0;
right: 0;
/* TODO Add browser prefixes */
background: linear-gradient( 45deg, transparent 33.333%, #2B3A48 33.333%, #2B3A48 66.667%, transparent 66.667%), linear-gradient( -45deg, transparent 33.333%, #2B3A48 33.333%, #2B3A48 66.667%, transparent 66.667%);
background-size: 8px 20px;
/* toothSize doubleHeight */
background-position: 0 -10px;
/* horizontalOffset -height */
}
<div class="header">
<h1>This is a header</h1>
</div>
<nav class="navbar"></nav>
Personally, I think clip-path is easier to work with/understand than complex background gradients.
body {
font-family:Roboto,'Open Sans',Helvetica,sans-serif;
}
.container {
background:#ddd;
margin:0 auto;
max-width:800px;
padding:30px;
}
h1:first-child {margin:0;}
.jagged-bottom {
position:relative;
}
.jagged-bottom:after {
background:#ddd;
content:"";
height:2vw;
position:absolute;
top:100%;
left:0;
right:0;
clip-path:polygon(
0 0, 2.5% 100%, 5% 0, 7.5% 100%,
10% 0,12.5% 100%,15% 0, 17.5% 100%,
20% 0,22.5% 100%,25% 0, 27.5% 100%,
30% 0,32.5% 100%,35% 0, 37.5% 100%,
40% 0,42.5% 100%,45% 0, 47.5% 100%,
50% 0,52.5% 100%,55% 0, 57.5% 100%,
60% 0,62.5% 100%,65% 0, 67.5% 100%,
70% 0,72.5% 100%,75% 0, 77.5% 100%,
80% 0,82.5% 100%,85% 0, 87.5% 100%,
90% 0,92.5% 100%,95% 0, 97.5% 100%, 100% 0);
}
<div class="container jagged-bottom">
<h1>Looks Like A Receipt</h1>
<p>Simply adjust the clip path on the pseudo-element if you want more or fewer spikes, and the height if you want them to be taller or shorter.</p>
</div>
There is a border-image property in CSS3.
Maybe you can work it out in a way you want. More here:
https://developer.mozilla.org/en-US/docs/Web/CSS/border-image
Or here
https://www.w3schools.com/cssref/css3_pr_border-image.asp
You can create an individual triangle using CSS quite easily (just tweak border properties). In order for this to work you will need to generate quite a bit of markup yourself. I would recommend against this approach.
Instead you are likely better off using an individual image containing a single triangle (preferably a transparent .png) and then use background-image and background-repeat (repeat-x) properties to bind that to a div (your "border").
Unfortunately there is no yet a straight-forward way to achieve this using pure CSS.

Resources