将图像置于响应式视口内,而不会丢失其纵横比

时间:2014-02-24 16:49:44

标签: javascript jquery html5 css3

我要做的是将视图居中并调整视图(或父元素)内部的图像,而不是拉伸它。

总而言之,我想让图像保持纵横比并调整大小以便完全覆盖视口。

这是我的HTML布局:

<div class="media-area" data-size="b" data-type="2">
   <ul class="content-slider">
       <li class="cs-item">
          <img class="cs-background" src="assets/img/backgrounds/top-slider-1.jpg" alt="slider-element">
       </li>
       <li class="cs-item">
          <img class="cs-background" src="assets/img/backgrounds/top-slider-2.jpg" alt="slider-element">
       </li>
       <li class="cs-item">
          <img class="cs-background" src="assets/img/backgrounds/top-slider-3.jpg" alt="slider-element">
       </li>
   </ul>
</div>

这是我的CSS:

.media-area {
    width: 100%;
    height: 100%; /* Standard height */
    position: relative;
    overflow: hidden;
}

.media-area .content-slider {
    position: relative;
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}

.media-area .content-slider .cs-item {
    position: relative;
    display: block;
    float: left;
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}

.media-area .content-slider .cs-item img {
    display: block;
}

.media-area .content-slider .cs-background {
    -webkit-transition: all .1s ease-in-out;
    -moz-transition: all .1s ease-in-out;
    -o-transition: all .1s ease-in-out;
    transition: all .1s ease-in-out;
}

这是我的JS:

function mediazone() {
var defaults = {
    elem: ".media-area",
    elemWrap: ".media-area .content-slider",
    elemSlide: ".media-area .content-slider .cs-item",
    vh: $(window).height(),
    vw: $(window).width()
};

$(defaults.elemSlide).find(".cs-background").each(function () {

    var bkndImgW = $(this).width();  // Current image width
    var bkndImgH = $(this).height(); // Current image height

    var mediaViewPortW = $(this).parents(defaults.elem).width();  // Current media viewport width
    var mediaViewPortH = $(this).parents(defaults.elem).height(); // Current media viewport height

    // Used for viewport aspect ratio
    var viewportratio = Math.round((mediaViewPortW / mediaViewPortH) * 100000 ) / 100000;  

    // Used for image aspect ratio
    var imageratio = Math.round((bkndImgW / bkndImgH) * 100000 ) / 100000;  

    // Negative margins for when the height is larger than the width
    var bkndImgPosW = ((bkndImgW - mediaViewPortW) / 2)*-1;

    // Negative margins for when the width is larger than the height
    var bkndImgPosH = ((bkndImgH - mediaViewPortH) / 2)*-1;

    bkndImgPosW = Math.min(0, Math.max(bkndImgPosW, bkndImgPosW)); 
    bkndImgPosH = Math.min(0, Math.max(bkndImgPosH, bkndImgPosH)); 

    if (viewportratio > imageratio) {            

        $(this).removeAttr("style");
        $(this).css("min-height", "100%");
        $(this).css("width", "100%");
        $(this).css("margin", bkndImgPosH+"px 0px");
    } else if (viewportratio < imageratio){

        $(this).removeAttr("style");
        $(this).css("height", "100%");
        $(this).css("min-width", "100%");
        $(this).css("margin", "0px "+bkndImgPosW+"px");
    } else if (viewportratio == imageratio) {
        $(this).removeAttr("style");
    }
});
}

该函数在此处初始化:

$(document).ready(function () {
    mediazone();
});
$(window).resize(function () {
    mediazone();
    console.log('window resize event');
});

我现在遇到的问题是,当页面加载时,图像离视口有一半,但是当我调整浏览器窗口大小时,它完全适合。

我现在无法找到解决方法的另一个问题是两个宽高比相等的问题(我找不到一种方法让图像覆盖屏幕而不必处理一些空格) 。当上述场景正在进行时,这会使图像闪烁。

重要的是我在DOM中使用IMG标记,否则可能会有一种方法来利用CSS中的“background-image”属性。

任何人都可以指出我错过了什么/做错了/我应该删除吗?

亲切的问候,

亚历

*稍后修改 *

这就是我现在所拥有的:

http://jsfiddle.net/LexEckhart/Z5cjx/

调整大小后,它似乎工作正常并保持图像在中间平衡,但是当页面加载时,项目定位不正确。

3 个答案:

答案 0 :(得分:1)

由于OP明确表示他不想使用背景图像,因为图像必须作为图像存在于DOM中,这里有一个显示解决方案的jsfiddle。我使用不透明度使图像变暗,以显示其下方的li的边框。我认为OP正在过度思考这个问题。无论如何,希望这会有所帮助。

jsfiddle

    if (viewportratio > imageratio) {            
        $(this).removeAttr("style");
        $(this).css("width", "100%");
        $(this).css("margin", bkndImgPosH+"px 0px");
    } else if (viewportratio < imageratio){
        $(this).removeAttr("style");
        $(this).css("height", "100%");
        $(this).css("margin", "0px "+bkndImgPosW+"px");
    } else if (viewportratio == imageratio) {
        $(this).removeAttr("style");
    }

请注意,如果您只提供一个属性/属性(宽度或高度),则图像会保留其宽高比。这是解决方案的关键。

编辑:更新了小提琴。我玩数学逻辑,直到它对我的图像起作用,替换我之前使用过的图像。第一部分下面的数学逻辑可能是错误的,所以它需要进一步测试,但这适用于我所拥有的。

答案 1 :(得分:0)

您可以利用百分比填充始终根据元素的宽度计算的事实。因此,您可以使用百分比宽度的垂直填充来强制使用宽高比。

<div id=img></div>

// ... then in CSS:

#img {
  background: url("http://placekitten.com/1280/720") no-repeat center center;
  background-size: cover;
  height: 0;
  padding-bottom: 56.25%; /* 9:16, or 720/1280 */
}

Here is a jsfiddle to demonstrate.如果你事先不知道宽高比,你当然可以计算它并通过JavaScript动态设置“padding-bottom”。

感谢此技术的inimitable Dave Rupert

编辑啊,隐藏了该结尾段落中的<img>标记。如果您确实需要<img>标记,则可以使用此技巧的变体:

<div class=image-centerer>
  <img src='http://whatever.com/your/image.png'>
</div>

// ... then in CSS:

.image-centerer {
  position: relative;
  height: 0;
  padding-bottom: 56.25%;
}
.image-centerer img {
  position: absolute;
  display: block;
  height: 100%;
}

Fiddle demohere is one demonstrating the handling of arbitrarily-proportioned images.

答案 2 :(得分:0)

你可以试试

&#34;背景大小&#34;和&#34;对齐项目&#34;来自css3的属性。

设置&#34;背景大小:100%100%;&#34 ;; 它将覆盖(父窗口);

要在中心对齐内容,您可以使用&#34; align-items:center&#34;。