CSS background-size: cover + background-attachment: fixed clipping background images

Mam listę figur zawierających obrazy tła. Coś w stylu:

<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>

Każdy z tych obrazów ma swój background-size ustawiony na cover i background-attachment ustawiony na fixed.

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

Gdy każda z figur zajmuje cały widok, działa to dobrze, ale jeśli jest przesunięcie dowolnego rodzaju, obraz tła zostaje obcięty.

Z tego, co wiem, Jest to projekt ( https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values).

Chciałbym, aby obrazy były klipowane pionowo lub poziomo, ale nie oba i były wyśrodkowane przez rozmiar samej figury.

Wiem, że istnieją rozwiązania javascript, ale czy istnieje sposób, aby to zrobić za pomocą CSS?

Oto działający przykład: http://codepen.io/Godwin/pen/KepiJ

Author: Godwin, 2014-02-14

9 answers

Niestety jest to po prostu artefakt tego, jak działa stałe pozycjonowanie w CSS i nie ma możliwości obejścia tego w czystym CSS - musisz użyć Javascript.

Powodem tego jest połączenie background-attachment: fixed i background-size: cover. Kiedy podasz background-attachment: fixed, to zasadniczo powoduje, że background-image zachowuje się tak, jakby był to obraz position: fixed, co oznacza, że jest wyjęty z kontekstu przepływu strony i pozycjonowania i staje się względny do widoku, a nie elementu jest to obraz tła z.

Więc za każdym razem, gdy używasz tych właściwości razem, wartość cover jest obliczana względem rozmiaru viewport niezależnie od rozmiaru samego elementu, dlatego działa zgodnie z oczekiwaniami, gdy element ma ten sam rozmiar co viewport, ale jest przycięty w nieoczekiwany sposób, gdy element jest mniejszy niż viewport.

Aby to obejść, musisz użyć background-attachment: scroll i powiązać detektor zdarzeń z zdarzeniami scroll w JS, które ręcznie aktualizują background-position względem tego, jak daleko okno zostało przewinięte, aby symulować stałe pozycjonowanie, ale nadal obliczać background-size: cover względem elementu kontenera, a nie widoku.

 60
Author: Ennui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-22 15:26:06

Jest do tego poprawka jQuery: http://jsfiddle.net/QN9cH/1 / Wiem, że nie jest optymalny, ale przynajmniej działa :)

$(window).scroll(function() {
  var scrolledY = $(window).scrollTop();
  $('#container').css('background-position', 'left ' + ((scrolledY)) + 'px');
});
 23
Author: Nick Noordijk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-18 14:17:11

Odpowiedź Nicka Noordijka postawiła mnie na dobrej drodze, ale lubię unikać skryptów, które wykonują obliczenia za każdym razem, gdy wystąpi zdarzenie przewijania. Oto moja wersja, która wykonuje obliczenia tylko po załadowaniu strony lub zmianie rozmiaru ekranu:

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 + '%');
}

Zauważ, że tak naprawdę działa tylko z obrazami "banerowymi" - używanie background-size: auto nn% nie ma tej samej przewagi background-size: cover w pracy bez względu na to, czy twój obraz ma nadmiar w w obu kierunkach.

 3
Author: squarecandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-13 22:44:01
background: url(<image>) center top no-repeat fixed;
background-size: auto <width size in %>;
Nie ma realnego rozwiązania. Można jednak ustawić rozmiar na wysokość obrazu auto zamiast cover. I dostosuj rozmiar szerokości w % w Twoim elemencie, aż ugryzie obramowanie. Jeśli zmienisz rozmiar okna, okno nie zostanie przycięte. Zamiast tego zawsze zachowa oryginalny format rozmiaru obrazu. Z tym powyżej w zasadzie "Powiększ" to, ale nie "zakryj" tego.
 3
Author: Thielicious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 16:18:35

Właściwość background-size: cover; rzeczywiście przycina obraz, aby wypełniał obszar i nie miał pustej przestrzeni.

Właściwość background-size: contain; określa, który wymiar jest większy i skaluje się zgodnie z tym. Więc jeśli masz blok 100px x 100px i obraz tła o wymiarach 200x150px, ustawienie rozmiaru tła spowoduje skalowanie obrazu do 100x75px. W tym scenariuszu jednak będziesz miał pustą przestrzeń, jeśli współczynnik proporcji elementu jest inny niż obraz.

Możesz również ręcznie kontrolować, która proporcja ma priorytet, zakładając, że znasz proporcje obrazu.

Więc jeśli wiesz, że twój obraz jest zawsze 100x200px, oznacza to, że szerokość jest zawsze Mały wymiar, a wysokość duży.

Teraz ustawienie background-size: 100% auto; zapewni, że nie otrzymasz pustej przestrzeni, ale skończysz z przycinaniem. Jeśli ustawisz go na background-size: auto 100%; zapewni to, że brak przycinania ma miejsce i wysokość nigdy nie będzie miała pustej przestrzeni (ale szerokość będzie).

Jeśli chcesz obcinać i wyśrodkować obraz, użyj background-position: 50%;.

 1
Author: kakashigr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-17 23:54:30

Przykład efektu paralaksy dla elementów ułożonych osobno (nie dla elementów pełnoekranowych):

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
Author: baduga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-04 19:15:58

Aktualizacja w lipcu 2018: jest teraz 1-liniowa poprawka dla tego problemu

Miałem ten sam problem, dopóki nie przeczytałem tego artykułu , który nauczył mnie, że mogę dodać tę linię do mojego CSS, aby to działało:

will-change: transform;

Udało się!

Teraz mój CSS wygląda tak:

.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;
    }
}
Działa mi na Windows Chrome, Edge i Safari. Ale nie Firefox.
 0
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-23 00:21:00

Innym bardzo prostym rozwiązaniem jest użycie jednostek vw i vh (które, gdybyś nie wiedział, ma całkowicie akceptowalne wsparcie dla przeglądarki w większości przypadków). Na przykład, zamiast robić background-size: cover, robić background-size: auto 100vh.

Jeśli nie znasz vw i vh, są to jednostki viewport i odpowiadają szerokości i wysokości viewport. Wartości odpowiadają procentowi wysokości lub szerokości viewportu. Na przykład 50vw oznacza 50% szerokości widoku.

Dla nasze cele, możemy po prostu powiedzieć, że tło jest 100% wysokości viewport.

Tu są skrzypce.

Jeśli chcesz dostosować różne proporcje obrazu, możesz skorzystać zaspect-ratio @media rules .

 0
Author: Pete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 15:46:31

Zrobiłem wersję z responsywnym obrazem tła.

.flexslider .slides > li {
  background-position: center center;
  background-repeat: no-repeat;
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
}
#slider,
.alink {
  min-height: 300px
}
.alink {
  display: block
}

Http://jsfiddle.net/onigetoc/grpku1gk/

 -6
Author: Gino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-30 06:33:23