web-dev-qa-db-fra.com

CSS background-size: cover + background-attachment: images d'arrière-plan coupées fixes

J'ai une liste de figures contenant des images de fond. Quelque chose comme ce qui suit:

<ul>
  <li>
    <figure style="background-image: url(...);"></figure>
  </li>
  <li>
    <figure style="background-image: url(...);"></figure>
  </li>
  <li>
    <figure style="background-image: url(...);"></figure>
  </li>
</ul>

Chacune de ces images a son background-size défini sur cover et son background-attachment défini sur fixed.

figure {
  width: 100%;
  height: 100%;
  background-size: cover;
  background-attachment: fixed;
}

Lorsque chacune des figures occupe la totalité de la fenêtre d'affichage, cela fonctionne correctement, mais s'il existe un décalage quelconque, l'image d'arrière-plan est coupée.

Autant que je sache, ceci est inhérent à la conception ( https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values ​​ ).

Je voudrais que les images soient coupées verticalement ou horizontalement mais pas les deux, et soient centrées sur la taille de la figure.

Je sais qu'il existe des solutions javascript, mais existe-t-il un moyen de le faire en utilisant CSS?

Voici un exemple de travail: http://codepen.io/Godwin/pen/KepiJ

33
Godwin

Malheureusement, ceci est simplement un artefact de la façon dont le positionnement fixe fonctionne en CSS et il n’est pas possible de le contourner en CSS pur - vous devez utiliser Javascript.

Cela s’explique par la combinaison de background-attachment: fixed et background-size: cover. Lorsque vous spécifiez background-attachment: fixed, le background-image se comporte comme s'il s'agissait d'une image position: fixed, ce qui signifie qu'il est extrait du contexte de flux de page et de positionnement et devient relatif à la fenêtre d'affichage plutôt qu'à l'élément dont elle est l'arrière-plan.

Ainsi, chaque fois que vous utilisez ces propriétés ensemble, la valeur cover est calculée par rapport à la taille de la fenêtre indépendamment de la taille de l'élément lui-même. C'est pourquoi il fonctionne comme prévu lorsque l'élément a la même taille que la fenêtre mais est recadré. de manière inattendue lorsque l'élément est plus petit que la fenêtre d'affichage.

Pour contourner ce problème, vous devez en principe utiliser background-attachment: scroll et lier un écouteur d'événement à l'événement scroll dans JS qui met à jour manuellement le background-position en fonction du degré de défilement de la fenêtre afin de simuler un positionnement fixe tout en calculant background-size: cover par rapport à l'élément conteneur plutôt que la fenêtre.

53
Ennui

Il y a un correctif jQuery pour ceci: http://jsfiddle.net/QN9cH/1/ .__ Je sais que ce n'est pas optimal mais au moins ça marche :) 

$(window).scroll(function() {
  var scrolledY = $(window).scrollTop();
  $('#container').css('background-position', 'left ' + ((scrolledY)) + 'px');
});
22
Nick Noordijk
background: url(<image>) center top no-repeat fixed;
background-size: auto <width size in %>;

Il n'y a pas de vraie solution. Cependant, vous pouvez définir la hauteur de l’image auto au lieu de cover. Et ajustez la taille de la largeur en% dans votre élément jusqu'à ce qu'il mord la bordure. 

Vous voyez, si vous redimensionnez votre fenêtre, elle ne sera pas coupée. Au lieu de cela, il conservera toujours le format de taille d'image original. Avec ce qui précède, vous «zoomez», mais ne le «recouvrez» pas.

2
Thielicious

La taille du fond: couverture; Cette propriété est en fait en train de découper l’image afin de remplir la zone et de ne pas avoir d’espace vide.

La taille du fond: contient; La propriété détermine quelle dimension est la plus grande et les échelles correspondantes. Donc, si vous avez un bloc de 100px x 100px et une image d’arrière-plan de 200x150px, définir la taille de l’arrière-plan à contenir permettra de redimensionner l’image à 100x75px. Cependant, dans ce scénario, vous aurez un espace vide si les proportions de l'élément sont différentes de celles de l'image. 

Vous pouvez également contrôler manuellement la proportion prioritaire, en supposant que vous connaissiez le format de l'image. 

Donc, si vous savez que votre image est toujours 100x200px, cela signifie que la largeur correspond toujours à la petite dimension et la hauteur à la grande. 

Définissez maintenant la taille de l’arrière-plan: 100% auto; veillera à ce que vous n'obteniez pas d'espace vide, mais vous vous retrouvez avec une coupure. Si vous le définissez à la taille de l’arrière-plan: auto 100%; cela garantira qu'aucune coupure ne se produit et que la hauteur n'aura jamais d'espace vide (mais la largeur le sera).

Si vous voulez découper et centrer simplement l'image, utilisez background-position: 50%;.

1
kakashigr

La réponse de Nick Noordijk m'a mis sur la bonne voie, mais j'aime éviter les scripts qui effectuent un calcul chaque fois que l'événement de défilement se produit. Voici ma version qui effectue le calcul uniquement lorsque la page est chargée ou que la taille de l'écran change:

html:

<div class="fake-img"></div>

css:

.fake-img {
    display: block;
    height: 280px;  /* set the height here */
    width: 100%;
    background-image: url('http://example.com/path/to/image.jpg');
    background-repeat: no-repeat;
    background-position: center 68px;
    background-size: auto 50%; /* make a "best guess" here as a default */
    background-attachment: fixed;
    position: relative;
}

jQuery:

$(window).on('resize load orientationchange', function(){
    responsive_calc();
});

var responsive_calc = function(){

    // get the viewport height
    var h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

    // get the element height
    var bannerHeight = $('.fake-img').height();

    // get the integer percentage value difference between them
    var bgHeightPercent = Math.ceil(bannerHeight/h*100);

    // set background-size height to match the element instead of the viewport
    $('.fake-img').css('background-size', 'auto ' + bgHeightPercent + '%');
}

Notez que cela ne fonctionne vraiment qu'avec des images "bannières" en mode paysage. L'utilisation de background-size: auto nn% ne présente pas le même avantage que background-size: cover, même si votre image présente un excès dans les deux sens.

0
squarecandy

Exemple d’effet de parallaxe pour des éléments disposés séparément (pas pour des éléments en plein écran):

html:

<div style="background-image: url('/path/to/image.jpg')">Content</div>

css:

#element_to_scroll {
    background-repeat: no-repeat;
    background-size: cover; 
    background-position-x: center; 
    background-position-y: 0;   
}

js:

$(window).scroll(function() {
    var realImageWidth = 1280;
    var realImageHeight = 1024;
    var viewportBottom = $(window).scrollTop() + $(window).height();
    $('#element_to_scroll').each(function(){
        var scrollAmountPx = realImageHeight/(realImageWidth/$(this).outerWidth())-$(this).outerHeight();
        var elementOffsetFromBottom = viewportBottom-$(this).offset().top;
        var scrollAreaHeight = $(this).outerHeight() + $(window).height();
        if(elementOffsetFromBottom>0 && elementOffsetFromBottom<scrollAreaHeight) {
            var backgroundPositionOffset = Math.ceil(scrollAmountPx/scrollAreaHeight*elementOffsetFromBottom);
            //$(this).css('background-position-y',"-"+backgroundPositionOffset+"px");
            $(this).clearQueue().animate({'background-position-y':"-"+backgroundPositionOffset+"px"},50);
        }
    });
});
0
baduga

Mise à jour en juillet 2018: il existe désormais un correctif sur une ligne pour ce problème.

J'ai eu ce même problème jusqu'à ce que je lis cet article , ce qui m'a appris que je pouvais ajouter cette ligne à mon CSS pour que cela fonctionne

will-change: transform;

Ça a marché!

Maintenant, mon CSS ressemble à ceci:

.myClass{
    position: relative;
    background: hsla(300, 100%, 90%, 0.1);
    overflow: hidden;
    &::before {
        background-image: url(/img/bg.jpg);
        background-size: cover;
        background-size: cover !important;
        -webkit-background-size: cover !important;
        background-repeat: repeat repeat !important;
        background-attachment: scroll !important;//"fixed" is the desired effect, but mobile browsers find it too "expensive" and disabled it, so use "scroll"
        background-position: 30% 50%;
        @media(min-width: $screen-sm-min){
            background-attachment: fixed !important;
            background-position: 30% 20%;
            will-change: transform;
        }//768
        content: "";
        display: block;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        opacity: 0.1;
    }
}

Cela fonctionne pour moi sur Windows Chrome, Edge et Safari. Mais pas Firefox.

0
Ryan

Une autre solution très simple consiste à utiliser les unités vw et vh (qui, si vous ne le saviez pas, disposent de prise en charge du navigateur totalement passable dans la plupart des cas). Par exemple, au lieu de faire background-size: cover, faites background-size: auto 100vh.

Si vous ne connaissez pas vw et vh, ce sont des unités de fenêtre d'affichage et elles correspondent à la largeur de la fenêtre et à la hauteur de la fenêtre. Les valeurs correspondent à un pourcentage de la hauteur ou de la largeur de la fenêtre. Par exemple, 50vw signifie 50% de la largeur de la fenêtre.

Pour nos besoins, nous pouvons simplement dire que l’arrière-plan correspond à 100% de la hauteur de la fenêtre.

Voici un violon.

Si vous avez besoin de prendre en compte différents formats, vous pouvez utiliser les règles format d'image @media .

0
Pete