Animated Image Header
I've been thinking a lot lately about what is the nature of a website and what is the design philosophy that we should be taking as web designers and developers. A website is contained but unrestrained. It is built but also two-dimensional. It must be flexible but able to be traversed easily. These sorts of dichotomies are not easy to take in and even more difficult to "get right." It is television, but interactive. It is a poster, but without borders or limits. Design can utilize three dimensions. It is at once a stack of paper and a broadsheet. In the end, the Web is what you make of it. That has been the goal, I suspect, of the W3C. Through the code they have approved and that browsers have implemented, a website can be anything we want it to be. This leaves open a lot of possibilities.
One such possibility is like broadcast TV. That's what I was thinking a few days ago while watching an event. I thought, "What about a documentary-style hero image that would slowly move as the user consumes some text information?" So I went out and created it. Here's the finished product:
The background image moves very slowly, zooming into the main focus of the image--the bears. The text supports the image and vice versa. Let's take a look at how to set this up.
The first snag I ran into was how to get the photo set up with the text over the image. I originally set the photo as a background image with a text overlay. That's simple enough, but I couldn't get the animation onto just the image. I didn't want the entire group of image and text to grow, just the image itself. So I needed to separate all of the elements and stack them using absolute positioning. Here's my final HTML:
<header class="hero">
<div class="hero-image"><img class="slow-grow" src="https://unsplash.it/3500?image=1020"/></div>
<div class="hero-text">
<h1>Grizzly bears have been reduced in the lower 48 states from an estimated historical population of 50,000 to only about 1,800 today in five small, isolated populations</h1><a class="button" href="#bear-facts">Learn More</a>
</div>
</header>
You can see that inside the header I've included my two elements: the image and the text. Layering them is a matter of adding position: relative
to the CSS of the header and then absolutely positioning the hero text and image. I added the z-index values just to make sure the elements stack in the order I want them to go. Here's the CSS:
.hero {
height: 100vh;
overflow: hidden;
position: relative;
font-family: "Alfa Slab One", cursive;
}
.hero-text {
padding-left: 2rem;
position: absolute;
top: 1rem;
left: 0;
width: 35vw;
z-index: 50;
}
.hero-text h1 {
text-shadow: 1px 1px 0px rgba(0, 0, 0, 0.2);
color: #fff;
margin: 0;
font-weight: 400;
}
.hero-image {
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
.hero-image img {
width: 100%;
margin-top: -25%;
-webkit-transform-origin: bottom right;
transform-origin: bottom right;
}
You'll notice that I've added overflow: hidden
to the image container. This allows me to grow the image inside of a "frame", so to speak. If you don't have this, the image might bleed into the rest of the text on the site.
Now, let's look at animating this image.
You could use Javascript, but I prefer using CSS when I can. The animation is instant on download and more performant. CSS animations are pretty easy to work with, but can take some time getting accustomed to the syntax. It's not your normal CSS. For a great overview with examples, check out this series of tutorials on CSS animation from the DevTips YouTube channel.
I created a class that I could add the animation to called .slow-grow
. Here is the CSS:
.slow-grow {
-webkit-animation: grow 150000ms ease;
animation: grow 150000ms ease;
}
@-webkit-keyframes grow {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
}
@keyframes grow {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
}
To create an animation in CSS, you have to first declare the animation through the @keyframes
rule. Then you give the animation a name. That name is what you use in the animation
property for the class or element that you want to animate. In this example, my animation is named grow
and I add that using the animation
property on the .slow-grow
class. Essentially, the animation makes the image scale up 1.5 times from the beginning of the animation (0%) to the end of the animation (100%).
There are some values that I can choose to customize the timing of the animation when I attach it to the class using the animation
property. I first need the name of the animation, then how long it should take, then what sort of movement or timing it needs. I chose to use the ease-in-out
function but could have easily gone with linear
as the value. It would look good, too.
The trickier part was the timing. I wanted this to be a super slow growing/zooming action. So I played a lot with the numbers here. There is a balanced relationship between how much the image scales and how fast the animation should be. The less distance it scales, the faster the timing needs to be. The larger the scaling, the slower the timing. Hopefully, that makes sense. You can play around with it and see what I'm talking about.
The final part of this entire equation is something powerful and kind of subtle. What direction do you want to scale from? The default is to scale the image up from the middle. The way you decide this is to look at where the text is and where the focus of the image is. I wanted to focus the user on the bears (bottom right) and keep the text at the top left. It made sense to scale the image from the bottom right because that's where I wanted to "zoom in." The point of this technique is to slowly draw the viewer into a particular part of the image. So choose that part of the image and set the the transform-origin
to zoom into that area. For this image, it was transform-origin: bottom right;
. You can use a wide range of finer measurements to get this just right. Play around with media queries, too, to make sure every device sees what you want them to see. I found that I needed to add this property to the image itself, not the container, since it was the image that I added the .slow-grow
class to.
Here's the finished product again:
It's a nice effect that can be added anywhere that you want to create some subtle movement. This would work really well anytime you're trying to create more emotion on a website.
Like it? Hate it? Can it be improved? Leave a comment below. I'd love to hear your thoughts! Feel free to fork this and use it in your own projects. If you think about it, come back and put a link to where you're using it online. I'd love to see this out in the wild!