web-dev-qa-db-ja.com

CSS background-size:カバー+ background-attachment:背景画像のクリッピングを修正

背景画像を含む図のリストがあります。次のようなもの:

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

これらの各画像には、background-sizeに設定coverおよびbackground-attachmentfixedに設定されます。

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

各図がビューポート全体を占める場合、これは正常に機能しますが、何らかの種類のオフセットがある場合、背景画像がクリップされます。

私の知る限り、これは設計によるものです( https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values )。

画像を両方ではなく垂直または水平にクリップし、フィギュア自体のサイズの中央に配置したいです。

Javascriptソリューションがあることは知っていますが、CSSを使用してこれを行う方法はありますか?

これが実際の例です: http://codepen.io/Godwin/pen/KepiJ

33
Godwin

残念ながら、これは単にCSSで固定位置がどのように機能するかの成果物であり、純粋なCSSでは回避できません。Javascriptを使用する必要があります。

これが発生する理由は、background-attachment: fixedbackground-size: coverの組み合わせによるものです。 background-attachment: fixedを指定すると、本質的にbackground-imageposition: fixed画像であるかのように動作します。つまり、ページフローと位置付けコンテキストから取り出され、背景画像である要素ではなくビューポートに対して相対的になります。

したがって、これらのプロパティを一緒に使用すると、エレメント自体のサイズに関係なく、ビューポートのサイズに対してcover値が計算されます。これが、エレメントがビューポートが、要素がビューポートより小さい場合、予期しない方法で切り取られます。

これを回避するには、基本的にbackground-attachment: scrollを使用し、イベントリスナをJSのscrollイベントにバインドして、固定位置をシミュレートするためにウィンドウがスクロールされた距離に対してbackground-positionを手動で更新し、なおかつbackground-size: coverを計算する必要がありますビューポートではなくコンテナ要素に関連します。

56
Ennui

これにはjQueryの修正があります: http://jsfiddle.net/QN9cH/1/ 私はそれが最適ではないことを知っていますが、少なくともそれは動作します:)

$(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 %>;

実際の解決策はありません。ただし、autoの代わりに画像のサイズをcoverにすることができます。そして、境界線に食い込むまで要素の幅サイズを%で調整します。

ウィンドウのサイズを変更すると、クリップされなくなります。代わりに、常に元の画像サイズ形式を維持します。上記を使用して、基本的に「ズーム」しますが、「カバー」しません。

2
Thielicious

背景サイズ:カバー;プロパティは実際に画像を切り取って、領域を埋め、空のスペースがないようにします。

Background-size:含む;プロパティは、どの次元が大きいかを決定し、それに応じてスケーリングします。したがって、100px x 100pxブロックと200x150pxの背景画像がある場合、背景サイズを含むように設定すると、画像は100x75pxにスケーリングされます。ただし、このシナリオでは、要素のアスペクト比が画像のアスペクト比と異なる場合、空のスペースがあります。

また、画像の縦横比がわかっている場合は、どの比率を優先するかを手動で制御することもできます。

したがって、画像が常に100x200pxであることがわかっている場合、これは幅が常に小さい寸法であり、高さが大きい寸法であることを意味します。

背景サイズの設定:100%auto;空のスペースを取得しないようにしますが、クリッピングが発生します。 background-sizeに設定した場合:auto 100%;クリッピングが発生せず、高さに空スペースが含まれないようにします(ただし、幅は空になります)。

クリッピングを行い、画像を中央に配置する場合は、background-position:50%;を使用します。

1
kakashigr

Nick Noordijkの答えは私を正しい道に導きましたが、スクロールイベントが発生するたびに計算を実行するスクリプトを避けるのが好きです。ページの読み込み時または画面サイズの変更時にのみ計算を実行する私のバージョンは次のとおりです。

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

これは実際に横長の「バナー」画像でのみ機能することに注意してください-background-size: auto nn%を使用しても、画像がどちらの方向に過剰な場合でもbackground-size: coverと同じ利点はありません。

0
squarecandy

個別に配置された要素の視差効果の例(フルスクリーン要素ではありません):

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

2018年7月の更新:この問題に対する1行の修正があります

この記事 を読むまでこの同じ問題を抱えていたので、CSSにこの行を追加して機能させることができると教えてくれました。

will-change: transform;

動いた!

CSSは次のようになります。

.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;
    }
}

Windows Chrome、Edge、Safariで動作します。しかし、Firefoxではありません。

0
Ryan

別の非常に簡単な解決策は、vwユニットとvhユニットを使用することです(知らない場合、ほとんどの場合、 完全に問題のないブラウザーサポート があります) 。たとえば、background-size: cover、 行う background-size: auto 100vh

vwvhに慣れていない場合、これらはビューポートの単位であり、ビューポートの幅とビューポートの高さに対応しています。値は、ビューポートの高さまたは幅の割合に対応します。例えば、 50vwは、ビューポート幅の50%を意味します。

この目的のために、背景をビューポートの高さの100%に単純に伝えることができます。

これはフィドルです

異なるアスペクト比に対応する必要がある場合は、 aspect-ratio @media rules を利用できます。

0
Pete