Is it possible to achieve such an effect in HTML5 and CSS3 , Please find the attached image
Here I have two divs with overflow:hidden, inside each is an image. And when I hover each image, the image zoom in or moves up or down inside this same div container. So basically the div works like a mask for the big image.
What I fail to achieve here is the shape of the div to mask the image. Is there a way to achieve that and can work in the latest versions of almost all browsers?
Thanks for you help !
For something like that, I would suggest two different possibilities:
Using CSS transformations (in particular skewY); or
Using SVG (with just some polygons)
Each of them has some good/bad things and will work in all the modern browsers and in mobile, as you can see in the caniuse.com website for transform and SVG.
Using CSS 2D Transformations
You would have a container div that would be skewed vertically, and then inside of it other divs with the skew (over)corrected. Then hiding the overflow so the excess of the contained divs is not shown.
You can see a demo here (or on this JSFiddle):
#skewed {
position:relative;
margin-top:20px;
width: 500px;
height: 300px;
transform: skewY(-2deg);
-webkit-transform: skewY(-2deg);
-moz-transform: skewY(-2deg);
-o-transform: skewY(-2deg);
overflow:hidden;
background:black;
-webkit-backface-visibility: hidden;
}
#skewed div {
position:absolute;
height:200px;
width:500px;
transform: skewY(4deg);
-webkit-transform: skewY(4deg);
-moz-transform: skewY(4deg);
-o-transform: skewY(4deg);
overflow:hidden;
opacity:0.4;
transition:all 0.5s;
z-index:1;
background-size:100% 100%;
-webkit-backface-visibility: hidden;
}
#skewed div:hover {
opacity:1;
z-index:2;
background-size:110% 110%;
}
#top {
top:-50px;
left:0;
background:url(http://lorempixel.com/1000/400/animals) no-repeat center center;
}
#bottom {
top:150px;
left:0;
background:url(http://lorempixel.com/1000/400/people) no-repeat center center;
}
<div id="skewed">
<div id="top"></div>
<div id="bottom"></div>
</div>
About this solution:
Supported by all major browsers (except Opera Mini), although you'll need to use prefixes.
Easy to implement and extend with further content (text, links, etc.)
In Chrome, the edges look too sharp. Although this can be fixed using -webkit-backface-visibility: hidden as suggested by Neven in this answer.
Using SVG
Use polygons to define the basic shapes that you want to create.
I am not a SVG-expert, so I can't do anything fancy, but this is to get a general idea. Here is a simple demo (you can also see it on this JSFiddle):
polygon {
opacity:0.4;
transition:all 0.5s;
}
polygon:hover {
opacity:1;
}
<svg width="500" height="300" viewBox="0 0 500 300">
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="600" height="300">
<image xlink:href="http://lorempixel.com/600/300/animals" x="0" y="0" width="600" height="300" />
</pattern>
<pattern id="img2" patternUnits="userSpaceOnUse" width="600" height="300">
<image xlink:href="http://lorempixel.com/600/300/people" x="0" y="0" width="600" height="300" />
</pattern>
</defs>
<polygon id="top" points="0,20 500,0 500,170 0,130" fill="url(#img1)" />
<polygon id="bottom" points="0,130 500,170 500,280 0,300" fill="url(#img2)" />
</svg>
About this solution:
Supported by all the major browsers (no need for prefixes or anything)
Highly customizable: I used polygons, but you could use paths and curves to give a more personal solution.
SVG is not as easy as the other solution (Ok, something as simple as this is easy, but something more complex will require some learning).
Related
So you can get pixelation in CSS by doing the following:
Set background-image to a very small image (say 50px or 100px).
Set image-rendering: pixelated on the element.
That will give you the pixelated look.
Now I would like to animate this, by replacing the "very small image" with a large image after it finishes downloading by the browser:
let img = new Image()
img.src = largeVersion
img.onload = function(){
// set css background-image to the new image perhaps, not sure...
}
The problem is two-fold.
I want to have the background-image using background-size: cover so it properly fills the container element. So you can't use background-size in any pixelation animation.
transform: scale(0.1) (to get close to the original pixelation size) doesn't work because it scales the whole element.
I would like to do something like this: animate transform: scale(x) to go from 50px pixelated image to 2000px unpixelated image, over 0.3 or 0.5 seconds. But that doesn't work. I thought maybe using background-size, but that doesn't work either because of the constraint.
Wondering if there is any way to accomplish this.
I have seen this which does pixelation using canvas. Wondering if there is no other solution that works without using JS/canvas.
<style>
div {
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
</style>
<div style='background-image: url(/100px.jpg)'></div>
You can do pixelation with an svg filter.
You can then animate the filter.
to use the filter on a div background you just do filter: url(#filterid)
put together it looks like this:
#myDiv::before{
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
filter:url(#pixelate);
background-size:cover;
background-image:url(https://images.unsplash.com/photo-1475724017904-b712052c192a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80)
}
#myDiv {
position:relative;
width:350px;
height:250px;
}
.inside {
position: relative;
}
<div id="myDiv"> <div class="inside"><h1>Hello</h1></div> </div>
<svg>
<filter id="pixelate" x="0" y="0">
<feFlood x="4" y="4" height="1" width="1" />
<feComposite id="composite1" width="10" height="10" />
<feTile result="a" />
<feComposite in="SourceGraphic" in2="a" operator="in" />
<feMorphology id="morphology" operator="dilate" radius="5" />
</filter>
<animate xlink:href="#composite1" id="anim-width"
attributeName="width" from="40" to="10" dur=".8s"
fill="freeze" />
<animate xlink:href="#composite1" id="anim-height"
attributeName="height" from="40" to="10" dur=".8s"
fill="freeze" />
<animate xlink:href="#morphology" id="anim-radius"
attributeName="radius" from="20" to="5" dur=".8s"
fill="freeze"/>
</svg>
Notice I had to create a inner div and apply the background on a pseudo-element ::before but "soon" this will become unnecessary, when the support of backdrop-filter improves.
references:
Pixelate svg effect: https://codesandbox.io/s/km3opvn6yv
Animate an svg filter: https://codepen.io/chriscoyier/pen/dPRVqL
backdrop-filter: https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter
HTML
<svg viewBox="0 0 1024 1024">
<path d="M624 96h16l192 224v576.295c0 34.963-28.617 63.705-63.918 63.705h-480.165c-35.408 0-63.918-28.759-63.918-64.235v-735.531c0-35.488 28.693-64.235 64.088-64.235h335.912zM608 128h-320.142c-17.595 0-31.858 14.568-31.858 31.855v736.291c0 17.593 14.551 31.855 31.999 31.855h480.003c17.672 0 31.999-14.238 31.999-31.789v-544.211h-128.067c-35.309 0-63.933-28.37-63.933-64.189v-159.811zM640 144v143.719c0 17.828 14.421 32.281 31.896 32.281h118.503l-150.398-176zM320 320v32h224v-32h-224zM320 224v32h224v-32h-224zM320 416v32h416v-32h-416zM320 512v32h416v-32h-416zM320 608v32h416v-32h-416zM320 704v32h416v-32h-416zM320 800v32h416v-32h-416z" />
</svg>
CSS
svg { width:20px; height:20px; }
output 1 (Firefox 57.0.2)
output 2 (Chrome 63.0)
Scaling the image as shown above makes it look blurry. (https://jsfiddle.net/wutx56co/)
If you know the solution, I would like to answer. Thanks.
try applying this
svg {
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
transform: translateZ(0);
}
The following code snippet illustrates my problem:
<style>
div {
background-color: #00FF00;
width: 80px;
}
svg {
background-color: #FF0000;
vertical-align: top;
width: 100%;
height: auto; // PROBLEM
}
rect { fill: #0000FF; }
</style>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
shape-rendering="geometricPrecision"
text-rendering="geometricPrecision"
image-rendering="optimizeQuality"
fill-rule="evenodd"
clip-rule="evenodd"
preserveAspectRatio="xMidYMid meet"
width="100"
height="100"
>
<rect width="90" height="90" x="5" y="5" />
</svg>
</div>
The SVG should be a red square (with a blue square drawn into it), which scales down with respect the its parent div tag while preserving its aspect ratio. The above example works fine in Firefox, Chrome (for Desktop and Android), Safari and Edge. It renders a 80x80px red square:
Only Internet Explorer 10 and 11 stretch the SVG vertically to about twice its intended height, so 80x160px:
The SVG is scaled to 80x100px if I remove / comment the "height: auto" statement in the stylesheet. Yet, this breaks Chrome, which also scales the SVG to 80x100px in this case. Firefox and Edge seem to be able to deal with removing this statement.
Interestingly, the aspect ratio of polygons etc. in the SVG is always perfectly maintained, check the blue square, while the polygons are usually drawn in the vertical center of the SVG which is being stretched. It's the "SVG-container"/SVG-tag, which causes trouble and consumes more space than it should.
How can I solve this cross-browser?
I built a small JSFiddle to demonstrate the issue.
There is a closely related question entitled "SVGs not scaling properly in IE - has extra space". The key difference is that I do in fact provide a width and a height directly in the svg-tag, which I need to do for Android browser compatibility. IE breaks nevertheless. The canvas-approach described by Paul LeBeau seems to follow different assumptions.
This question is a variation of the following older questions, yet not identical:
Cross browser SVG preserveAspectRatio
SVG in img element proportions not respected in ie9
SVG scaling in Internet Explorer
The following gist is interesting but not helpful either:
Fix SVG in tags not scaling in IE9, IE10, IE11 (it really is about SVGs in img-tags and removing the width and height parameters in the SVG tag does not work for me)
There is an approach called the "padding hack", which is described here:
CSS tricks: How to Scale SVG
Making SVGs Responsive with CSS
This answer is only for reference - I am still looking for a better, less complicated (and less idiotic) way to do this.
Ok, along the lines of the "padding hack", the following seems to work across browsers:
<style>
div#outer {
background-color: #00FF00;
width: 80px;
}
div#container {
position: relative;
height: 0;
width: 100%;
padding: 0;
padding-bottom: 100%; /* 100% * height/width */
}
svg {
background-color: #FF0000;
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
}
rect { fill: #0000FF; }
</style>
<div id="outer">
<div id="container">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
shape-rendering="geometricPrecision"
text-rendering="geometricPrecision"
image-rendering="optimizeQuality"
fill-rule="evenodd"
clip-rule="evenodd"
preserveAspectRatio="xMidYMid meet"
width="100"
height="100"
>
<rect width="90" height="90" x="5" y="5" />
</svg>
</div>
</div>
There is also an updated JSFiddle.
Another Solution is the Padding-Bottom Hack (Padding-Bottom: Width/Height*100)
Here an example with responsive svg-clippath and ie11+up support
<svg class="clipper" width="0" height="0">
<defs>
<clipPath id="clippath" clipPathUnits="objectBoundingBox" transform="scale(0.01, 0.01136364)">
<path d="M78.24,5.09S75.53.46,70.15.46H29.85s-5.38,0-8.09,4.63L1.66,39.37S-1,44,1.66,48.63l20.1,34.28s2.71,4.63,8.09,4.63h40.3s5.38,0,8.09-4.63l20.1-34.28s2.71-4.63,0-9.26Z"></path>
</clipPath>
</defs>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 88" preserveAspectRatio="xMidYMin slice" style="width: 100%; padding-bottom: 88%; height: 1px; overflow: visible">>
<image xlink:href="http://www.domain.de/image-with-aspect-ratio-100-88.jpg" x="0" y="0" height="100%" width="100%" style="clip-path: url(#clippath);">
</image>
</svg>
I have a <div> that has a background-color sitting in front of an image. I'm trying to apply a multiply effect using an SVG so that the background image behind the div comes through:
<svg>
<filter id="multiply">
<feBlend mode="multiply"/>
</filter>
</svg>
Unfortunately, only the solid background color is being changed, and I get no transparency through to the background.
Here's the fiddle: https://jsfiddle.net/0p58bxsp/1/
The effect I'm expecting is something like this:
I know the visual effect could be fudged using an rgba value as the background color, but I'm very specifically looking for the combination of a solid color having a multiply filter applied to it.
Is this a limitation of the current SVG implementation?
Here's the definition of a multiply blend:
Multiply blend mode multiplies the numbers for each pixel of the top layer with the corresponding pixel for the bottom layer. The result is a darker picture. , where a is the base layer value and b is the top layer value.
As such, using opacity or alpha doesn't give me the exact result that I'm looking for.
This was supposed to be possible if you stayed completely within SVG 1.1 by using the BackgroundImage pseudo input - but only IE10 ever supported it for inline SVG (Opera supported it for .svg files). Firefox, Chrome & Safari never supported it, and it's now formally declared "not to be implemented" by folks who work on those browsers.
You can import a copy of the background image using feImage and position it just right to match the actual background exactly. But depending on your design - that could take extensive javascript. And url() filters can behave strangely. https://jsfiddle.net/0p58bxsp/3/ shows how to do this - but it also surfaces a regression bug in Chrome with positioned primitives which will be fixed in next Chrome.
<div id="background">
<div id="effect">
Effect goes here
</div>
</div>
<svg width="100%" height="100%" viewBox="0 0 200 200">
<defs>
<filter id="multiply" x="0%"
y="0%" height="300%" width="300%">
<feImage x="0" width="400" height="400" y="0" preserveAspectRatio="xMaxYMax meet" xlink:href="http://lorempixel.com/400/400/" />
<feOffset dx="-100" dy="-100"/>
<feBlend mode="multiply" in="SourceGraphic"/>
</filter>
</defs>
</svg>
Safari 9(and only Safari 9) has a "backdrop-filter" that will do this, and you can also specify a mix-blend-mode which has broader support, but this is still pretty edge.
If you need a multiply blend, it might be best to just keep everything in SVG.
You should add opacity: 0.4; into effect class. It will work fine.
#effect {
color: #fff;
height: 200px;
margin: 100px 0 0 100px;
width: 200px;
opacity: 0.4;
background-color: #3d3934;
filter: url(#multiply);
-webkit-filter: url(#multiply);
-moz-filter: url(#multiply);
}
As far as I know, svg effects are limited to the elements itself. You can't use it to mix with another element.
You can however get this effect with standard CSS mix-blend-mode
#background {
background-image: url(http://lorempixel.com/400/400/);
height: 400px;
padding: 1px;
width: 400px;
}
#effect {
color: #fff;
height: 200px;
margin: 100px 0 0 100px;
width: 200px;
background-color: gray;
mix-blend-mode: multiply;
}
<div id="background">
<div id="effect">
Effect goes here
</div>
</div>
I want to create a perspective crop like effect with CSS3 like this:
I did try it doing my self but couldn't, any help would be appreciated.
here's my attempt: http://jsfiddle.net/krish7878/y9eusob9/
HTML Code:
<div class="container">
<img src="http://img.netcarshow.com/Lotus-Evora_GX_Racecar_2013_1600x1200_wallpaper_01.jpg" alt="main image" />
</div><!-- /.container -->
CSS Code:
.container{
overflow: hidden;
width: 300px;
height: 200px;
margin-top: 30px;
margin-left: 30px;
border-top-right-radius: 20px;
}
One option could be to add a container <div>, e.g..perspective, that gets the yellow background color and to use a polygon clip-path on the image.
A good tool to create these polygons is Bennett Feely's clippy. Browser support for clip-path isn't quite there yet though. See Clipping and Masking in CSS for more background information and options.
.perspective {
display: inline-block;
background-color: #ff0;
}
.perspective__image {
display: block;
-webkit-clip-path: polygon(10% 20%, 90% 10%, 90% 90%, 10% 80%);
clip-path: polygon(10% 20%, 90% 10%, 90% 90%, 10% 80%);
}
<div class="perspective">
<img src="http://www.nicenicejpg.com/400/300" class="perspective__image"/>
</div>
You might be able to accomplish this effect using a layering technique like what is found here:
http://cssglobe.com/angled-content-mask-with-css/
Basically, the author used a few nested elements that were rotated back and forth with overflow: hidden on the container elements.
For maximum browser support you could use svg's clipPath.
<svg width="400" height="400">
<defs>
<clipPath id="shape">
<path d="M50,50 L400,0 L400,400 L50,350" />
</clipPath>
</defs>
<foreignObject clip-path="url(#shape)" width="400" height="400">
<img src="http://www.lorempixel.com/400/400" />
</foreignObject>
</svg>
I found a great tutorial on css-tricks that talks about doing exactly this:
http://css-tricks.com/almanac/properties/p/perspective/
You'll be making use of the transform property to make the rotations you need to simulate the perspective change.
Hope this helps!