【问题标题】:Keep div overlay relative to background image regardless of window size无论窗口大小如何,保持 div 覆盖相对于背景图像
【发布时间】:2014-11-19 09:52:57
【问题描述】:

我想用background-size: cover 在背景图像上覆盖一些文本。

这里的问题是,无论窗口大小如何,我如何将叠加 div 保持在相对于背景图像的相同位置?

这里有一个小提琴:http://jsfiddle.net/resting/2yr0b6v7/

所以我想将单词 eye 放在猫的眼睛上方,而不管窗口大小。

欢迎使用 CSS 或 JS 解决方案。

【问题讨论】:

  • 它会移动一点,但将其保持在该区域内的一种快速方法是使用 % 而不是 px 给它它的位置
  • 已经尝试过%,但它实际上移动了很多位置。也许它不可能有一个相对于背景图像的 div 覆盖。在我看来,它总是相对于窗口。
  • jsfiddle.net/f4yovb09/1/embedded/result 检查它是否像我提到的那样使用 % 来调整大小?

标签: javascript jquery html css


【解决方案1】:

编辑:添加了 js 替代品

我确信这可以用 css 完成并几乎放弃了,但后来我想起了新的 (ish) css 单元 vh and vw....

jsfiddle

CSS

html, body{
    height: 100%;
    width: 100%;
}
.cat {
    height: 100%;
    width: 100%;
    position: relative;
    background:url(http://placekitten.com/g/800/400) no-repeat center center / cover;
}
.place-on-eye {
    position: absolute;
    color: #fff;
    margin:0;
}

@media (min-aspect-ratio: 2/1) {    
    .place-on-eye {
        bottom: 50%;
        left: 46.875%;
        margin-bottom: 1.25vw;
    }
}

@media (max-aspect-ratio: 2/1) {   
    .place-on-eye {
        bottom: 52.5%;
        left: 50%;
        margin-left: -6.25vh;
    }
}

说明

所以左眼大约在 375、190 处,由于图像居中,我们还想知道它离中心有多远,所以 25、10。由于图像是覆盖的,所以图像的大小图像将根据视口的纵横比是大于还是小于背景图像的纵横比而改变。知道了这一点,我们可以使用媒体查询来定位文本。

图像是2:1,所以当视口纵横比>2:1时,我们知道图像的宽度就是视口的宽度,所以<p>的左边位置应该一直是46.867 % (375/800)。底部位置将变得更加困难,因为图像超出了视口顶部和底部。我们知道图片居中,所以先把<p>移到中间,然后再往上推图片高度的2.5%(10/400)。我们不知道图像的高度,但我们知道图像的纵横比,并且图像的宽度等于视口的宽度,因此 2.5% 的高度 = 1.25% 的宽度。所以我们必须将底部向上移动 1.25% 的宽度,我们可以通过设置 margin-bottom:1.25vw 来做到这一点。顺便说一句,在这种情况下,我们可以不使用vw 来执行此操作,因为填充始终是相对于宽度计算的,所以我们可以设置padding-bottom:1.25%,但是在下一个您必须定位左侧相对位置的情况下,这将不起作用到高度。

纵横比margin-left:-6.25vh.

希望这是正确的,可以帮助你!

JS 替代方案

jsfiddle

这是一个使用 js 的替代方案。它使用了一些功能,例如 forEach 和 bind,这可能会导致问题,具体取决于您需要使用它的浏览器的年龄,但它们很容易替换。使用js可以直接计算bg图片的缩放尺寸,让定位更容易。不是最优雅的代码,但这里是:

//elem:     element that has the bg image
//features: array of features to mark on the image
//bgWidth:  intrinsic width of background image
//bgHeight: intrinsic height of background image
function FeatureImage(elem, features, bgWidth, bgHeight) {
    this.ratio = bgWidth / bgHeight; //aspect ratio of bg image
    this.element = elem;
    this.features = features;
    var feature, p;
    for (var i = 0; i < features.length; i++) {
        feature = features[i];
        feature.left = feature.x / bgWidth; //percent from the left edge of bg image the feature resides
        feature.bottom = (bgHeight - feature.y) / bgHeight; //percent from bottom edge of bg image that feature resides               
        feature.p = this.createMarker(feature.name);
    }
    window.addEventListener("resize", this.setFeaturePositions.bind(this));
    this.setFeaturePositions(); //initialize the <p> positions
}

FeatureImage.prototype.createMarker = function(name) {
    var p = document.createElement("p"); //the <p> that acts as the feature marker
    p.className = "featureTag";
    p.innerHTML = name;
    this.element.appendChild(p);
    return p
}

FeatureImage.prototype.setFeaturePositions = function () {
    var eratio = this.element.clientWidth / this.element.clientHeight; //calc the current container aspect ratio
    if (eratio > this.ratio) { // width of scaled bg image is equal to width of container
        this.scaledHeight = this.element.clientWidth / this.ratio; // pre calc the scaled height of bg image
        this.scaledDY = (this.scaledHeight - this.element.clientHeight) / 2; // pre calc the amount of the image that is outside the bottom of the container
        this.features.forEach(this.setWide, this); // set the position of each feature marker
    }
    else { // height of scaled bg image is equal to height of container
        this.scaledWidth = this.element.clientHeight * this.ratio; // pre calc the scaled width of bg image
        this.scaledDX = (this.scaledWidth - this.element.clientWidth) / 2; // pre calc the amount of the image that is outside the left of the container
        this.features.forEach(this.setTall, this); // set the position of each feature marker
    }
}

FeatureImage.prototype.setWide = function (feature) {
    feature.p.style.left = feature.left * this.element.clientWidth + "px";
    feature.p.style.bottom = this.scaledHeight * feature.bottom - this.scaledDY + "px"; // calc the pixels above the bottom edge of the image - the amount below the container
}

FeatureImage.prototype.setTall = function (feature) {
    feature.p.style.bottom = feature.bottom * this.element.clientHeight + "px";
    feature.p.style.left = this.scaledWidth * feature.left - this.scaledDX + "px"; // calc the pixels to the right of the left edge of image - the amount left of the container
}

var features = [
    {
        x: 375,
        y: 190,
        name: "right eye"
    },
    {
        x: 495,
        y: 175,
        name: "left eye"
    },
    {
        x: 445,
        y: 255,
        name: "nose"
    },
    {
        x: 260,
        y: 45,
        name: "right ear"
    },
    {
        x: 540,
        y: 20,
        name: "left ear"
    }
];

var x = new FeatureImage(document.getElementsByClassName("cat")[0], features, 800, 400);

【讨论】:

  • 谢谢!小提琴完美无缺,它使用了我喜欢的新 CSS 规范。但是,我现在必须采用旧学校的方法。
  • 更新我意识到如果位置不在中心附近,其他解决方案就会中断。
  • 有没有vw vh 替代品?我想如果我们能弄清楚背景是如何调整大小的,我认为应用相同的算法应该可以用背景图像正确缩放叠加层。
  • 我已经添加了一个js版本。对于 css 版本,我认为您需要 vw/vh,因为我无法想到基于垂直度量水平微调某些东西。不过,我可能错了。您可以使用填充基于水平测量垂直微调,但反之则不行。如果有人阅读,我很想知道在没有 vh 的情况下在 css 中执行此操作。
  • 我添加了我的 JS 解决方案,借鉴了两种解决方案的原则。但这并不完全准确。
【解决方案2】:

我做了一个fiddle 借用了 2 个答案的原则。黑点应覆盖在行尾。但是这个解决方案与实际点有一定比例的偏差。

也许有人可以改进它?

JS:

$(function() {
    function position_spot() {
        w = $(window).width();
        h = $(window).height();
        wR = w/h;

        // Point to place overlay based on 1397x1300 size
        mT = 293;
        mL = -195;

        imgW = 1397;
        imgH = 1300;
        imgR = imgW/imgH;

        tR = mT / imgH; // Top ratio
        lR = mL / imgW; // Left ratio

        wWr = w / imgW; // window width ratio to image
        wHr = h / imgH; // window height ratio to image

        if (wR > imgR) {
            // backgroundimage size
            h = imgH * wWr;
            w = imgW * wWr;
        } else {
            h = imgH * wHr;
            w = imgW * wHr;
        }
        $('.overlay-spot').css({
            'margin-top': h * tR,
            'margin-left': w * lR
        });
    }
    $(window).resize(function() {
        position_spot();
    });
    position_spot();

});

【讨论】:

  • 我试图弄清楚为什么这有一段时间不起作用。一切看起来都正确,我认为它是正确的,只是我终于注意到实际图像宽度是 1379 像素而不是 1397 像素。那应该可以解决它!
  • 你是对的。它是 1379 像素。看起来不错:)。更新了小提琴。
【解决方案3】:

根据你设置背景图片的位置和大小:

background-position:center center;
background-size:cover;

背景图像的中心仍应位于屏幕的中心 - 作为常量派上用场,因此请尝试对您的 p.place-on-eye 执行相同操作

.place-on-eye {
    ...
    top: 50%;
    left: 50%;
}

现在段落的左上角位于屏幕的中心,如果您还添加宽度和高度属性,您实际上可以将元素中心定位到屏幕的中心。就像这样:

.place-on-eye {
    ...
    width:50px;
    height:50px;
    text-align:center /* to make sure the text is center according to elements width */
    top: 50%;
    left: 50%;
    margin:-25px 0 0 -25px;
}

所以现在p.place-on-eye 的中心位于屏幕的正中心,就像背景图像的中心一样。要使其越过猫眼,只需根据需要偏移左边距和上边距即可。

所以像margin:-27px 0 0 -60px; 这样的东西应该这样做。

fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 2016-01-14
    • 2011-09-10
    • 2021-04-20
    • 2014-05-26
    相关资源
    最近更新 更多