So you can get pixelation in CSS by doing the following:
background-image
to a very small image (say 50px or 100px).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.
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