Scale background image maintaining appearance

3

I am creating an adaptive image gallery where thumbnails of the image are displayed in squares. For this I put the background images using background-image and so that the image occupies the whole square, I use background-size:cover .

This works regardless of the size of the image (the different background images will have different sizes) and the images conform to the size of the container div without problems:

#gallery .squared { 
  height:0; 
  padding-top:50%; 
  background:#ab00ff; 
  position:relative; 
  color:white; 
  font-size:1.2em; 
  background-position:center center; 
  background-size:cover; 
}

@media (min-width: 768px) {
  #gallery .squared { padding-top:25%; }
}

@media (min-width: 992px) {
  #gallery .squared { padding-top:16.66%; }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<section id="gallery" class="section container-fluid">
  <div class="row">
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/people);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/300/nature);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/500/cats);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/500/300/sports);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/abstract);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/400/animals);"></div>
  </div>
</section>

Now I want to add some animation and when the user moves the mouse over the squares the background image grows a bit, for example 10%. But I can not find a way to do it. I have tried changing the value of background-size to 100% and in :hover to 110%, but it does not work well because that percentage is with respect to the container and not the size of the image, so, although the effect works , the landscape images do not finish looking good (they are repeated):

#gallery .squared { 
  height:0; 
  padding-top:50%; 
  background:#ab00ff; 
  position:relative; 
  color:white; 
  font-size:1.2em; 
  background-position:center center; 
  background-size:100%; 
  transition:all 1s;
}

#gallery .squared:hover { 
  background-size:110%; 
}

@media (min-width: 768px) {
  #gallery .squared { padding-top:25%; }
}

@media (min-width: 992px) {
  #gallery .squared { padding-top:16.66%; }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<section id="gallery" class="section container-fluid">
  <div class="row">
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/people);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/300/nature);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/500/cats);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/500/300/sports);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/abstract);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/400/animals);"></div>
  </div>
</section>

To avoid repeating it, I could do something like background-repeat: no-repeat but that's not what I want because there would be blank spaces in some squares.

So the question would be: Is it possible to do this exclusively with HTML and CSS without using JavaScript ?

    
asked by Alvaro Montoro 13.05.2016 в 06:24
source

3 answers

3

One quick solution I can think of is using ::before , those pseudo-elements can help a lot in some cases (like this one). It's something 'hackish' but it can give you an idea.

You could use ::before with visibility in hidden or visible, in the latter case you would not need the background image that you declare in the inline style of each div in the gallery.

One disadvantage is that the ::before can not be used in an inline style, you would have to add a <style>...</style> for each div in case you are generating them with a loop or similar.

#gallery .squared { 
  height:0; 
  padding-top:50%; 
  background:#ab00ff; 
  position:relative; 
  color:white; 
  font-size:1.2em; 
  background-position:center center; 
  background-size:cover; 
  transition:all 1s;
  overflow:hidden;
}

#gallery .squared::before {
  background-image:url(http://lorempixel.com/300/200/people);
  content: " ";
  height:100%;
  width:100%;
  position:absolute;
  top:0;
  left:0;
  background-size:cover;
  visibility:hidden; /* puede ser visible también */
}

#gallery .squared:hover::before {
  background-image:url(http://lorempixel.com/300/200/people);
  height:110%;
  width:110%;
  content: " ";  
  position:absolute;
  top:-5%;
  left:-5%;
  transition:all 1s;
  visibility:visible;
}

#gallery .squared:hover { 
  background-size:110%; 
}

@media (min-width: 768px) {
  #gallery .squared { padding-top:25%; }
}

@media (min-width: 992px) {
  #gallery .squared { padding-top:16.66%; }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<section id="gallery" class="section container-fluid">
  <div class="row">
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/people);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/300/nature);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/500/cats);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/500/300/sports);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/200/abstract);"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2" style="background-image:url(http://lorempixel.com/300/400/animals);"></div>
  </div>
</section>
    
answered by 13.05.2016 / 07:12
source
2

I have an alternative and I explain my reasons.

The part I do not like to use :before for this task is that it is very complicated to style the elements when the url of the images is not yet known.

You should not change the background-size: cover style since it will give you the best possible image adjustment so both displaying the image and animating it should leave this property as it is.

This is to your liking but I prefer to use transform with transform: scale(X) instead to change width: 110% , height: 110% or background-size: 110% , is less compatible but the reason is that when you use dimensions it is more complicated to control the origin of the animation. Animating with transform: scale will always do it from the center and if you want to change that you can use transform-origin . If you use dimensions you will have to constantly adjust left , top , etc depending on the style you have chosen.

To achieve what you want, simply create a new element within each of your divs with class .squared . I used the class .thumb . Using position: absolute is mandatory since the .squared element is collapsed with height: 0 but since the container has position: relative there is no risk to get out of place. This has exactly the same effect as using :before but without the problems that this entails and you have more freedom to use inline styles.

Check the demo that I leave you.

#gallery .squared {
  height: 0;
  padding-top: 50%;
  position: relative;
  overflow: hidden;
}
#gallery .squared .thumb {
  position: absolute;
  background-size: cover;
  transition: all 1s;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}
#gallery .squared .thumb:hover {
  transform: scale(1.5);
}
#gallery .squared:hover {
  background-size: 110%;
}
@media (min-width: 768px) {
  #gallery .squared {
    padding-top: 25%;
  }
}
@media (min-width: 992px) {
  #gallery .squared {
    padding-top: 16.66%;
  }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<section id="gallery" class="section container-fluid">
  <div class="row">
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image:url(http://lorempixel.com/300/200/people);"></div>
    </div>
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image: url(http://lorempixel.com/300/300/nature);"></div>
    </div>
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image: url(http://lorempixel.com/300/500/cats);"></div>
    </div>
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image: url(http://lorempixel.com/500/300/sports);"></div>
    </div>
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image: url(http://lorempixel.com/300/200/abstract);"></div>
    </div>
    <div class="squared col-xs-6 col-sm-3 col-md-2">
      <div class="thumb" style="background-image: url(http://lorempixel.com/300/400/animals);"></div>
    </div>
  </div>
</section>

Now you can reuse this snipet of css without having to modify a line of code, you just have to change the urls of your images, which you can easily achieve with a repeater in the language you are using.

    
answered by 18.05.2016 в 16:59
0

Thanks to the Shaz response , I was able to find a way to do it using the pseudo-element ::before (I had obfuscated trying to do it directly, without thinking about other alternatives). What I did was:

  • Use the original container as a frame with a overflow:hidden to avoid showing content that exceeds its size.
  • Add the pseudo-element :before that occupies 100% of the size of the container and that has as a background image the image that I want with background-size:cover .
  • When the mouse passes over the container, make the pseudo-element larger (changing the position as well) and the style background-size:cover will take care of the rest.

The final result was like this:

#gallery .squared { 
  height:0; 
  padding-top:50%; 
  position:relative; 
  overflow:hidden;
}

#gallery .squared::before {
  content: " ";
  position:absolute;
  background-size:cover;
  transition:all 0.25s linear;
  height:100%;
  width:100%;
  top:0;
  left:0;
}

#gallery .squared:hover:before {
  content: " ";  
  height:110%;
  width:110%;
  top:-5%;
  left:-5%;
}

.img0::before { background-image:url(http://lorempixel.com/300/200/people); }
.img1::before { background-image:url(http://lorempixel.com/300/300/nature); }
.img2::before { background-image:url(http://lorempixel.com/300/500/cats); }
.img3::before { background-image:url(http://lorempixel.com/500/300/sports); }
.img4::before { background-image:url(http://lorempixel.com/300/200/abstract); }
.img5::before { background-image:url(http://lorempixel.com/300/400/animals); }

#gallery .squared:hover { 
  background-size:110%; 
}

@media (min-width: 768px) {
  #gallery .squared { padding-top:25%; }
}

@media (min-width: 992px) {
  #gallery .squared { padding-top:16.66%; }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />

<section id="gallery" class="section container-fluid">
  <div class="row">
    <div class="squared col-xs-6 col-sm-3 col-md-2 img0"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2 img1"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2 img2"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2 img3"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2 img4"></div>
    <div class="squared col-xs-6 col-sm-3 col-md-2 img5"></div>
  </div>
</section>
    
answered by 17.05.2016 в 22:19