Image hover effect – breaking into pieces

In this guide I'll show you how to use background-size and background-position CSS properties to break image into pieces and put it back together

In this guide I’ll show you how to use background-size and background-position CSS properties to break image into pieces and put it back together.

Full video guide: https://www.youtube.com/watch?v=fKVDnOJqtXM

  1. 1) Let’s start with HTML markup
<div class="portrait">
    <div class="part part-1"></div>
    <div class="part part-2"></div>
    <div class="part part-3"></div>
    <div class="part part-4"></div>
    <div class="part part-5"></div>
    <span class="portrait_title">
       Title
    </span>
</div>

and give some basic CSS styles to our parent <div> with a class of “portrait”

.portrait {
    top: 0;
    width: 200px;
    height: 295px;
    margin: 15px;
    position: relative;
    transition: 1s;
    margin: 50px auto;
}

2) All of it’s children <div>s will be used as pieces of our breaking image. I gave them two classes, “part” class to apply general styles …

.part {
    border: 1px solid rgba(0,0,0,0);
    position: absolute;
    background-repeat: no-repeat;
    transition: 1s;
    background-image: url('animal.jpg')
}

… and “part-1”, “part-2” etc to position each piece individually. We could also use :nth-of-type() or :nth-child() selector for the same purpose


3) As you can see, we are not using <img> element, instead we use background-image set with CSS.

.part {
    ...
    background-image: url('animal.jpg')
}

Before we position our pieces together we need to understand two CSS properties.

background-position sets the initial position for each background image developer.mozilla.org/background-position

background-size sets the size of the element’s background image developer.mozilla.org/background-size

Now we can position each background image so that together they create one picture. For more details on how I arrived at these specific values you can watch YouTube video guide (link on the top):

.part-1 {
    width: 60%;
    height: 90px;
    background-position: -50px 0;
    background-size: 250%;
}
.part-2 {
    width: 40%;
    height: 90px;
    top: 0;
    left: 60%;
    background-position: -157px 0;
    background-size: 364%;
}
.part-3 {
    width: 50%;
    height: 210px;
    top: 90px;
    left: 50%;
    background-position: -153px -94px;
    background-size: 310%;
}
.part-4 {
    width: 50%;
    height: 100px;
    top: 90px;
    background-position: -53px -94px;
    background-size: 310%;
}
.part-5 {
    width: 50%;
    height: 110px;
    top: 190px;
    background-position: -53px -194px;
    background-size: 310%;
}

4) Now everything is ready to apply hover effect. First I want to give each part visible border and box shadow to create 3D effect:

.portrait:hover .part {
    border: 1px solid rgba(0,0,0,1);
    box-shadow: 5px 2px 10px rgba(0,0,0,.8);
    transition: .3s cubic-bezier(.04,1.55,.66,1.12);
}

Notice that “transition” property was declared again for the same element(“.part”), this time specifically on hover. This way the pieces quickly bounce on hover and slowly slide back on mouse leave. It’s a common practice if you want your “mouse-enter” and “mouse-leave” transitions to have different timings, declare one transition on base element and another one for hover.

5) Position individual parts on hover with transform-translate:

.portrait:hover .part-1 {
    transform: translate(-1px, -5px);
}
.portrait:hover .part-2 {
    transform: translate(5px, -5px);
}
.portrait:hover .part-3 {
    transform: translate(5px, 55px);
}
.portrait:hover .part-4 {
    transform: translate(-1px, 55px);
}
.portrait:hover .part-5 {
    transform: translate(-1px, 60px);
}

Always try to use “transform:translate” instead of changing values of “top”, “left”… It performs better as it doesn’t cause layout re-flow.


6) Apply basic CSS styles for title, we start with transform: scale(.4) and opacity: 0. Also notice we can apply multiple box-shadows to a single element with a comma separated list:

.portrait_title {
    border: 1px solid black;
    text-align: center;
    font-size: 45px;
    position: absolute;
    top: 90px;
    left: -5%;
    width: 110%;
    height: 50px;
    line-height: 48px;
    transform: scale(.4);
    transform-origin: top;
    transition: .5s;
    box-shadow: 5px 2px 10px rgba(0,0,0,.5),
                inset 1px 3px 3px rgba(0,0,0,.5), 
                inset -1px -1px 5px rgba(0,0,0,.9);
    opacity: 0;
    text-shadow: 1px 2px 10px black;
}

7) On hover we just scale the title up, make it visible and give it some bounce with cubic-bezier:

.portrait:hover .portrait_title {
    transform: scale(1);
    opacity: 1;
    transition: .3s cubic-bezier(.04,1.55,.66,1.12);
}

And that’s our final effect complete. More guides coming soon!

Final HTML:

<div class="portrait">
    <div class="part part-1"></div>
    <div class="part part-2"></div>
    <div class="part part-3"></div>
    <div class="part part-4"></div>
    <div class="part part-5"></div>
    <span class="portrait_title">
       Title
    </span>
</div>

Final CSS:

.portrait {
    top: 0;
    width: 200px;
    height: 295px;
    margin: 15px;
    position: relative;
    transition: 1s;
    margin: 50px auto;
}
.part {
    border: 1px solid rgba(0,0,0,0);
    position: absolute;
    background-repeat: no-repeat;
    transition: 1s;
    background-image: url('animal.jpg')
}
.part-1 {
    width: 60%;
    height: 90px;
    background-position: -50px 0;
    background-size: 250%;
}
.part-2 {
    width: 40%;
    height: 90px;
    top: 0;
    left: 60%;
    background-position: -157px 0;
    background-size: 364%;
}
.part-3 {
    width: 50%;
    height: 210px;
    top: 90px;
    left: 50%;
    background-position: -153px -94px;
    background-size: 310%;
}
.part-4 {
    width: 50%;
    height: 100px;
    top: 90px;
    background-position: -53px -94px;
    background-size: 310%;
}
.part-5 {
    width: 50%;
    height: 110px;
    top: 190px;
    background-position: -53px -194px;
    background-size: 310%;
}
.portrait:hover .part {
    border: 1px solid rgba(0,0,0,1);
    box-shadow: 5px 2px 10px rgba(0,0,0,.8);
    transition: .3s cubic-bezier(.04,1.55,.66,1.12);
}
.portrait:hover .part-1 {
    transform: translate(-1px, -5px);
}
.portrait:hover .part-2 {
    transform: translate(5px, -5px);
}
.portrait:hover .part-3 {
    transform: translate(5px, 55px);
}
.portrait:hover .part-4 {
    transform: translate(-1px, 55px);
}
.portrait:hover .part-5 {
    transform: translate(-1px, 60px);
}
.portrait_title {
    border: 1px solid black;
    text-align: center;
    font-size: 45px;
    position: absolute;
    top: 90px;
    left: -5%;
    width: 110%;
    height: 50px;
    line-height: 48px;
    transform: scale(.4);
    transform-origin: top;
    transition: .5s;
    box-shadow: 5px 2px 10px rgba(0,0,0,.5),
                inset 1px 3px 3px rgba(0,0,0,.5),
                inset -1px -1px 5px rgba(0,0,0,.9);
    opacity: 0;
    text-shadow: 1px 2px 10px black;
}
.portrait:hover .portrait_title {
    transform: scale(1);
    opacity: 1;
    transition: .3s cubic-bezier(.04,1.55,.66,1.12);
}

Leave a Reply