将包含内容的div按比例缩放以适应窗口大小

34

我有一个固定大小的 <div>,其中包含一些复杂的内容(包括文本和背景图像)。这个 <div> 在像素中有其大小的硬编码(其内容也取决于此大小,并且内容位置也以像素为硬编码)。

这里是一个大大简化的例子:http://jsfiddle.net/dg3kj/

我需要缩放该div及其内部的内容,保持其纵横比,使其适合窗口。

首选不需要我手动更改 <div> 内容的解决方案(它是动态生成的,并且是一堆非常混乱的遗留代码,我想避免触摸)。 JavaScript(jQuery)解决方案可以(包括更改生成的内容的方案——只要在生成后执行即可)。

我尝试使用 transform: scale(),但效果不理想。请参见这里:http://jsfiddle.net/sJkLn/1/。(我希望红色背景不可见,即最外层的 <div> 大小不应由缩小的 <div> 的原始尺寸拉伸。)

有什么线索吗?


1
你只是想缩放 div 的大小,还是希望它的内容也随之缩放?例如,所有的图片都应该加倍大小等等? - James Montagne
1
如果你使用百分比设置 div 大小变量,然后在加载后使用 JS 添加宽度和高度,会怎样呢? - Michael
@JamesMontagne:我也需要扩展内容。已更新问题。 - Alexander Gladysh
@Michael:不太明白你的意思,抱歉 :-( - Alexander Gladysh
@dc5:我已经举了一个例子来解释为什么 scale() 对我不起作用。(我在那里使用了固定的比例——我想一旦我掌握了原理,就应该能够通过 JS 找出解决办法...) - Alexander Gladysh
显示剩余3条评论
6个回答

42

let outer = document.getElementById('outer'),
        wrapper = document.getElementById('wrap'),
        maxWidth  = outer.clientWidth,
        maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){let scale,
    width = window.innerWidth,
  height = window.innerHeight,
  isMax = width >= maxWidth && height >= maxHeight;

    scale = Math.min(width/maxWidth, height/maxHeight);
    outer.style.transform = isMax?'':'scale(' + scale + ')';
    wrapper.style.width = isMax?'':maxWidth * scale;
    wrapper.style.height = isMax?'':maxHeight * scale;
}
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  background: #e6e9f0;
  margin: 10px 0;
}


#wrap {
  position: relative;
  width: 640px;
  height: 480px;
  margin: 0 auto;
}
#outer {
  position: relative;
  width: 640px;
  height: 280px;
  background: url('https://source.unsplash.com/random') no-repeat center center;
  transform-origin: 0% 50%;
  border-radius: 10px;
  box-shadow: 0px 3px 25px rgba(0, 0, 0, 0.2);
  overflow: hidden;
}
#outer:before {
  content: "";
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 100px;
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

#profile {
  background: url('https://source.unsplash.com/random/300x300') no-repeat center center;
  position: absolute;
  width: 60px;
  height: 60px;
  bottom: 0;
  margin: 20px;
  border-radius: 100px;
  background-size: contain;
}
#content {
  font-size: 20px;
  position: absolute;
  left: 0px;
  bottom: 0;
  margin: 30px 100px;
  color: white;
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}

#content div:last-child {
  font-size: 15px;
  opacity: 0.7;
}
<div id="wrap">
<div id="outer">
  <div id="profile"></div>
  <div id="content">
    <div>Monwell Partee</div>
    <div>UX / UI Designer</div>
  </div>
</div>
</div>


1
可以了,谢谢!不过有一个问题,它没有考虑周围的填充和边距... - Alexander Gladysh
1
很高兴它能正常工作。你应该可以调整数学计算以适应你的布局 - 我选择了一种简便的方法来演示使用width()/height()。 - dc5
这非常有用!!不过,Firefox 有解决方法吗? - PrimalScientist
谢谢dc5,这很有用!@PrimalScientist 如果你注意到代码中有“-webkit-transform”,你可以将其替换为“transform”,或者添加任何其他旧的现代浏览器支持,如“-moz-transform”。 - jihchuan
这个可以运行,但是在CSS中使用百分比时要小心。百分比可能会基于缩放后的宽度而不是最大宽度(原始宽度)进行计算。 - kenecaswell
1
我采用了你的答案,并编写了一个简单的函数,它也可以在没有jquery的情况下工作。 function scaleBasedOnWindow(elm,scale=1){elm.style.transform='scale('+scale/Math.min(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';} - SwiftNinjaPro

6
我从dc5的答案中获取了内容,并将其放在一个小函数中,使您可以根据窗口设置比例尺。
function scaleBasedOnWindow(elm, scale=1, fit=false){
    if(!fit){
        elm.style.transform='scale('+scale/Math.min(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';
    }else{
        elm.style.transform='scale('+scale/Math.max(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';
    }
}

如果您希望元素完全适应,而不是被截断,则只需将 Math.min 更改为 Math.max ,或者将此函数的 fit 参数设置为 true。

压缩版本:

function scaleBasedOnWindow(elm,scale=1,fit){if(!fit){elm.style.transform='scale('+scale/Math.min(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';}else{elm.style.transform='scale('+scale/Math.max(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';}}

1

基于 dc5 的答案,纯JS实现;
根据 窗口大小调整 进行缩放。

let outer = document.getElementById('outer'),
        wrapper = document.getElementById('wrap'),
        maxWidth  = outer.clientWidth,
        maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){let scale,
    width = window.innerWidth,
  height = window.innerHeight,
  isMax = width >= maxWidth && height >= maxHeight;

    scale = Math.min(width/maxWidth, height/maxHeight);
    outer.style.transform = isMax?'':'scale(' + scale + ')';
    wrapper.style.width = isMax?'':maxWidth * scale;
    wrapper.style.height = isMax?'':maxHeight * scale;
}
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  background: #e6e9f0;
  margin: 0;
  padding: 0;
}


#wrap {
  position: relative;
  width: 640px;
  height: 480px;
  margin: 0 auto;
}
#outer {
  position: relative;
  width: 640px;
  height: 280px;
  background: url('https://source.unsplash.com/random') no-repeat center center;
  transform-origin: 0% 50%;
  border-radius: 10px;
  box-shadow: 0px 3px 25px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  margin-top: 10px;
}
#outer:before {
  content: "";
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 100px;
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

#profile {
  background: url('https://source.unsplash.com/random/300x300') no-repeat center center;
  position: absolute;
  width: 60px;
  height: 60px;
  bottom: 0;
  margin: 20px;
  border-radius: 100px;
  background-size: contain;
}
#content {
  font-size: 20px;
  position: absolute;
  left: 0px;
  bottom: 0;
  margin: 30px 100px;
  color: white;
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}

#content div:last-child {
  font-size: 15px;
  opacity: 0.7;
}
<div id="wrap">
<div id="outer">
  <div id="profile"></div>
  <div id="content">
    <div>Monwell Partee</div>
    <div>UX / UI Designer</div>
  </div>
</div>
</div>


1

如果有人正在构建一个全屏应用程序,比如1920x1080,并希望完美适配较小的屏幕 - 例如1366x768。这是我在Vue.js中所做的 - 但可以使用纯js和css完成 - 基于上面的答案 - 主要重要性在于我特别设置了原始宽度和高度,否则对我来说无法正常工作:

App.vue (如果localStorage中存在lowres,则为条件类)

    <template>
        <div id="external-app-wrapper" :class="{lowres: isLowRes}">
            <div id="internal-app-wrapper">
                <router-view />
            </div>
        </div>
   </template>

computed: {

      isLowRes() {
         return localStorage.getItem('lowres') !== null
      }
}

比例计算如下:1366/1920和786/1080

    #external-app-wrapper {
        width: 1920px;
        height: 1080px;
    }

    .lowres #internal-app-wrapper {
        transform-origin: top left;
        transform: scale(0.71145833333, 0.71111111111);
    }

router.js(分辨率可选)

       {
            path: '/app/:resolution?',
            name: 'App Home',
            component: () => import('@/components/routes/HomeRoute'),
            meta: {
                title: 'App Home'
            }
        }


在HomeRoute.vue文件中,我有以下内容:
        mounted() {
            if (this.$route.params.resolution === 'lowres') {
                localStorage.setItem('lowres', 'true')
                this.$router.push({ path: '/app' })
                this.$router.go()
            } else if (this.$route.params.resolution === 'highres') {
                localStorage.removeItem('lowres')
                this.$router.push({ path: '/app' })
                this.$router.go()
            }
        }

所以,导航到/app/lowres会重定向到/app并缩小整个应用程序,而导航到/app/highres会重定向到/app并恢复分辨率正常。
希望有人觉得这很有用 :)

-2
如果您需要根据窗口动态设置此内容,您也可以将div设置为可用窗口房地产的百分比。
    jQuery(document).ready(function ($) {
        var percentChange = .66;
        var newWidth = $(window).width() * percentChange; 
        $('#primary').css('width', newWidth + 'px');
    });

不幸的是,这无法扩展 div 内容。 - Alexander Gladysh
如果有人仍在引用此评论,请注意该评论是不正确的。 div 中的内容只需要处于流程中即可。 - L00c33
1
但是OP表示内容不是流动的,而是静态硬编码的内容。因此你的解决方案不起作用。 - Maksim Luzik
不,实际上,“#outer”是相对定位,所以它在流中。去看看jsfiddle吧。只有子元素“text”不在流中。无论如何,父元素都会硬编码高度/宽度,因此您不需要使用js来解决大部分问题。这个人所要做的就是将所需的百分比偏移量设置为子元素的边距。问题解决了。 - L00c33

-2
只要将内容的尺寸设置为基于百分比,就可以根据外部 div 动态调整它们的大小。然后只需使用 jQuery:
jQuery(document).ready(function ($) {
    var newWidth = '300px';
    $('.your-div').css('width', newWidth);
});

很不幸,内容位置也是以像素为单位的。我已经更新了问题以澄清这一点。 - Alexander Gladysh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接