【问题标题】:Scale div with its content to fit window使用其内容缩放 div 以适应窗口
【发布时间】:2013-09-11 20:36:59
【问题描述】:

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

这是一个非常简化的示例:http://jsfiddle.net/dg3kj/

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

不需要我手动更改<div> 内容的解决方案是可取的(它是动态生成的,是一堆非常混乱的遗留代码,我想避免接触)。 JavaScript (jQuery) 解决方案是可以的(包括更改生成内容的解决方案——只要它是在生成本身的事后完成的)。

我尝试使用transform: scale(),但没有产生令人满意的结果。见这里:http://jsfiddle.net/sJkLn/1/。 (我希望红色背景不可见 - 即最外层的 <div> 大小不应被按比例缩小的 <div>原始 尺寸拉伸。)

有什么线索吗?

【问题讨论】:

  • 你只是打算缩放 div 的大小还是希望它的内容也能缩放?例如,所有图像都应该翻倍吗?
  • 如果你使用 % 设置你的 div 大小变量,然后在加载后使用 js 添加宽度和高度?
  • @JamesMontagne:我还需要缩放内容。更新了问题。
  • @Michael:不确定我是否关注,抱歉 :-(
  • 好吧,如果你想让 div 适应窗口大小,请使用 100% 之类的相对大小进行调整,但你的内容需要固定大小,所以使用 javascript 将 100% 更改为加载后的实际宽度/高度。如果我们有一个 jsfiddle.net 示例来说明您要完成的工作,我们可能会为您提供更好的帮助。

标签: jquery html css


【解决方案1】:

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>

【讨论】:

  • 它有效,谢谢!但一个问题是它没有考虑周围的填充和边距......
  • 很高兴它有效。您应该能够调整数学以适应您的布局 - 我使用 width()/height() 走捷径进行演示
  • 这个很有用!!但是,Firefox 有解决方法吗?
  • 感谢 dc5 这很有用! @PrimalScientist 如果您注意到代码中有“-webkit-transform”,您可以将其替换为“transform”或添加任何其他较旧的现代浏览器支持,例如“-moz-transform”
  • 这行得通,但要小心在你的 CSS 中有百分比。然后可以根据缩放宽度而不是 maxWidth(原始宽度)计算百分比。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    如果有人构建一个全屏应用程序,比如说 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);
        }
    

    路由器.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 并且分辨率恢复正常

    希望有人觉得它有用:)

    【讨论】:

      【解决方案4】:

      纯JS基于dc5的回答;
      基于window resize的缩放

      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>

      【讨论】:

        【解决方案5】:

        只要您根据 % 确定内容的尺寸,那么您当然可以根据外部 div 动态调整它们的大小。然后只需使用 jQuery:

        jQuery(document).ready(function ($) {
            var newWidth = '300px';
            $('.your-div').css('width', newWidth);
        });
        

        【讨论】:

        • 不幸的是,内容位置也是以像素为单位的。我已经更新了问题以澄清这一点。
        【解决方案6】:

        如果您需要根据窗口动态设置它,您也可以将 div 设置为可用窗口不动产的百分比。

            jQuery(document).ready(function ($) {
                var percentChange = .66;
                var newWidth = $(window).width() * percentChange; 
                $('#primary').css('width', newWidth + 'px');
            });
        

        【讨论】:

        • 很遗憾,这不会缩放 div 内容。
        • 如果有人还在引用这个。这个评论是不正确的。 div 内的内容只需要处于流动状态。
        • 但是 OP 声明内容不是流动的,而是静态硬编码的内容。因此,您的解决方案不起作用。
        • 不,实际上,“#outer”是相对位置的,所以它是流动的。去看看jsfiddle。只有子元素“文本”没有流动。无论哪种方式,父元素的高度/宽度都是硬编码的,因此您不需要 js 来解决大部分问题。这个人所要做的就是简单地将他们想要的百分比偏移设置为子元素的边距。瞧;问题解决了。
        猜你喜欢
        • 2017-10-11
        • 1970-01-01
        • 2023-03-18
        • 2012-03-08
        • 2013-04-02
        • 1970-01-01
        • 1970-01-01
        • 2017-04-08
        • 2015-04-28
        相关资源
        最近更新 更多