CSS background-size: cover + background-attachment: 固定剪裁背景图片

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21786272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 01:52:32  来源:igfitidea点击:

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

cssbackground-imagebackground-attachmentbackground-size

提问by Godwin

I have a list of figures containing background images. Something like the following:

我有一个包含背景图像的数字列表。类似于以下内容:

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

Each of these images has their background-sizeset to coverand background-attachmentset to fixed.

这些图像中的每一个都background-size设置为coverbackground-attachment设置为fixed

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

When each of the figures takes up the entire viewport, this works fine, but if there is an offset of any kind the background-image gets clipped.

当每个图形占据整个视口时,这可以正常工作,但是如果存在任何类型的偏移,背景图像就会被剪裁。

As far as I can tell this is by design (https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values).

据我所知,这是设计使然https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values)。

I would like the images to either clip vertically or horizontally but not both, and be centred by the size of the figure itself.

我希望图像可以垂直或水平剪切,但不能同时剪切,并以图形本身的大小为中心。

I know there are javascript solutions but is there a way to do this using CSS?

我知道有 javascript 解决方案,但有没有办法使用 CSS 来做到这一点?

Here is a working example: http://codepen.io/Godwin/pen/KepiJ

这是一个工作示例:http: //codepen.io/Godwin/pen/KepiJ

回答by Ennui

Unfortunately this is simply an artifact of how fixed positioning works in CSS and there is no way around it in pure CSS - you have to use Javascript.

不幸的是,这只是 CSS 中固定定位如何工作的一个神器,在纯 CSS 中没有办法解决它——你必须使用 Javascript。

The reason this happens is due to the combination of background-attachment: fixedand background-size: cover. When you specify background-attachment: fixedit essentially causes the background-imageto behave as if it were a position: fixedimage, meaning that it's taken out of the page flow and positioning context and becomes relative to the viewport rather than the element it's the background image of.

之所以出现这种情况是由于组合background-attachment: fixedbackground-size: cover。当您指定background-attachment: fixed它时,它本质上会导致background-image表现得好像它是一个position: fixed图像,这意味着它被从页面流和定位上下文中取出并变得相对于视口而不是它作为背景图像的元素。

So whenever you use these properties together, the covervalue is being calculated relative to the size of the viewport irrespective of the size of the element itself, which is why it works as expected when the element is the same size as the viewport but is cropped in unexpected ways when the element is smaller than the viewport.

因此,无论何时一起使用这些属性,cover都会相对于视口的大小计算该值,而与元素本身的大小无关,这就是为什么当元素与视口大小相同但被裁剪时它按预期工作的原因当元素小于视口时的意外方式。

To get around this you basically need to use background-attachment: scrolland bind an event listener to the scrollevent in JS that manually updates the background-positionrelative to how far the window has been scrolled in order to simulate fixed positioning but still calculate background-size: coverrelative to the container element rather than the viewport.

为了解决这个问题,您基本上需要使用background-attachment: scroll并将事件侦听器绑定到scrollJS 中的事件,该事件手动更新background-position相对于窗口滚动的距离以模拟固定定位,但仍然background-size: cover相对于容器元素而不是视口进行计算.

回答by Nick Noordijk

There's a jQuery fix for this: http://jsfiddle.net/QN9cH/1/I know it's not optimal but at least it works :)

对此有一个 jQuery 修复:http: //jsfiddle.net/QN9cH/1/我知道它不是最佳的,但至少它有效:)

$(window).scroll(function() {
  var scrolledY = $(window).scrollTop();
  $('#container').css('background-position', 'left ' + ((scrolledY)) + 'px');
});

回答by squarecandy

Nick Noordijk's answer put me on the right track, but I like to avoid scripts that perform a calculation every time the scroll event happens. Here's my version that only performs the calculation when page loads or screen size changes:

Nick Noordijk 的回答使我走上了正确的轨道,但我喜欢避免每次发生滚动事件时执行计算的脚本。这是我的版本,仅在页面加载或屏幕尺寸更改时执行计算:

html:

html:

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

css:

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:

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

Note that this really only works with landscape "banner" images - using background-size: auto nn%doesn't have the same advantage of background-size: coverin working no matter if your image has excess in either direction.

请注意,这实际上仅适用于横向“横幅”图像 -无论您的图像在任一方向上是否有多余,使用background-size: auto nn%都没有与background-size: cover工作相同的优势。

回答by Thielicious

background: url(<image>) center top no-repeat fixed;
background-size: auto <width size in %>;

There is no real solution. However, you could make size height of the image autoinstead of cover. And adjust the width size in % in your element until it bites the border.

没有真正的解决方案。但是,您可以使图像的大小高度auto而不是cover. 并在元素中以 % 为单位调整宽度大小,直到它咬住边框。

You see if you resize your window, it won't be clipped. Instead, it will always keep the original image size format. With this above you basically 'zoom' it but doesn't 'cover' it up.

你看你是否调整你的窗口大小,它不会被剪裁。相反,它将始终保持原始图像大小格式。有了上面的内容,您基本上可以“放大”它,但不会“掩盖”它。

回答by kakashigr

The background-size: cover; property is indeed clipping the image in order for it to fill the area and not have any empty space.

背景尺寸:封面;属性确实在裁剪图像,以便它填充该区域并且没有任何空白空间。

The background-size: contain; property is determining which dimension is larger and scales according to that. So if you have a 100px x 100px block and a background image of 200x150px, setting the background-size to contain will scale the image to 100x75px. In this scenario however, you will have empty space if the element's aspect ratio is different than the image's.

背景大小:包含;属性正在确定哪个维度更大,并据此进行缩放。因此,如果您有一个 100px x 100px 的块和 200x150px 的背景图像,将 background-size 设置为 contains 会将图像缩放为 100x75px。但是,在这种情况下,如果元素的纵横比与图像的纵横比不同,您将有空白空间。

You can also manually control which proportion has priority, assuming you know the image's aspect ratio.

假设您知道图像的纵横比,您还可以手动控制哪个比例具有优先权。

So if you know that your image is always 100x200px, this means that the width is always the small dimension and the height the large one.

所以如果你知道你的图片总是 100x200px,这意味着宽度总是小尺寸,高度总是大尺寸。

Now setting the background-size: 100% auto; will ensure that you will not get empty space but you will end up with clipping. If you set it to background-size: auto 100%; it will ensure that no clipping takes place and the height will never have empty space ( but the width will).

现在设置背景尺寸:100% 自动;将确保您不会得到空白空间,但最终会被剪裁。如果将其设置为 background-size: auto 100%; 它将确保不会发生剪裁,并且高度永远不会有空白空间(但宽度会)。

If you do want clipping and just center the image, use background-position: 50%;.

如果您确实想要裁剪并且只是将图像居中,请使用 background-position: 50%;。

回答by baduga

An example of parallax effect for separately arranged elements (not for fullscreen elements):

单独排列元素的视差效果示例(不适用于全屏元素):

html:

html:

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

css:

css:

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

js:

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

回答by Ryan

Update in July 2018: There is now a 1-line fix for this problem

2018 年 7 月更新:现在有针对此问题的 1 行修复

I had this same problem until I read this article, which taught me that I could add this line to my CSS to make it work:

在我阅读这篇文章之前,我遇到了同样的问题,它教会我可以将这一行添加到我的 CSS 中以使其工作:

will-change: transform;

will-change: transform;

It worked!

有效!

Now my CSS looks like this:

现在我的 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;
    }
}

It's working for me on Windows Chrome, Edge, and Safari. But not Firefox.

它在 Windows Chrome、Edge 和 Safari 上对我有用。但不是火狐。

回答by Pete

Another very simple solution is to use of the vwand vhunits (which, in case you didn't know, has totally passable browser supportfor most cases). For example, instead of doing background-size: cover, do background-size: auto 100vh.

另一个非常简单的解决方案是使用vwandvh单位(如果您不知道,它在大多数情况下具有完全可通过的浏览器支持)。例如,与其做background-size: cover,不如做background-size: auto 100vh

If you're not familiar with vwand vh, they're viewport units, and they correspond to viewport width and viewport height. The values correspond to a percentage of the viewport height or width. For example, 50vwmeans 50% of the viewport width.

如果您不熟悉vwand vh,它们是视口单位,它们对应于视口宽度和视口高度。这些值对应于视口高度或宽度的百分比。例如,50vw表示视口宽度的 50%。

For our purposes, we can simply tell the background to be 100% of the viewport height.

出于我们的目的,我们可以简单地告诉背景为视口高度的 100%。

Here's a fiddle.

这是一个小提琴。

If you need to accommodate for different aspect ratios you can take advantage of the aspect-ratio @media rules.

如果您需要适应不同的宽高比,您可以利用宽高比 @media 规则

回答by Gino

I did a version with Responsive background image.

我做了一个带有响应式背景图片的版本。

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

http://jsfiddle.net/onigetoc/grpku1gk/